作ったプログラムの備忘録
はじめに
1次元配列でgrid表示させる方法で、カレンダー表示させてみました。
日付ウィジェットの配置は単純化できますが、日祝土曜日の色変化やヘッダー部分など含めると、結果的にウィジェット配置のコードもそこそこ長くなってしまったなと言う感じです。
動作テスト環境
OS: Windows 10 Pro 64bit
言語: Python 3.9.13
曜日表示
テキストが1文字ずつなので、f'{"日月火水木金土"[i]}'
とすればループで表示可能です。
土日のみ後から文字色を変更しています。
# 曜日表示
self.youbi = [tk.Label(self.frame2, text=f'{"日月火水木金土"[i]}') for i in range(7)]
[self.youbi[i].grid(row=0, column=i, padx=3, pady=5, sticky=tk.NSEW) for i in range(7)]
self.youbi[0].configure(fg='crimson')
self.youbi[6].configure(fg='navy')
カレンダー表示
self.bom
はdef days_setting(self):
で設定したその月の1日の曜日(isoweekday()
:月曜が1、日曜が7を返す関数)で、その値を足して行番号と列番号を計算することで、表示させています。
日祝判定はnot jpbizday.is_bizday(year, month, day)
で実施し、土曜は列番号から判定させています。
self.calender = []
for i in range(self.eom):
tmp = tk.Button(self.frame2, text=f'{i+1}', relief=tk.GROOVE,
command=partial(self.click_date, i+1))
tmp.grid(row=(self.bom + i)//7+1, column=(self.bom + i)%7, padx=3, pady=5, sticky=tk.NSEW)
if (self.bom + i)%7 == 6:
tmp.configure(fg='navy')
elif not jpbizday.is_bizday(datetime.date(self.now_year, self.now_month, i+1)):
tmp.configure(fg='crimson')
self.calender.append(tmp)
ソースコード
import datetime
import calendar
import jpbizday
import tkinter as tk
from tkinter import messagebox as mb
from functools import partial
class Application(tk.Frame):
def __init__(self, master = None):
super().__init__(master)
self.master.title('calendar')
self.master.geometry('420x360')
self.master.grid_rowconfigure(1, weight=1)
self.master.grid_columnconfigure(0, weight=1)
# 変数初期値設定
self.now_year = datetime.datetime.now().year
self.now_month = datetime.datetime.now().month
self.days_setting()
self.create_widgets()
def create_widgets(self):
# 年月表示フレーム
self.frame1 = tk.Frame(self.master)
self.frame1.grid(row=0, column=0, sticky=tk.NSEW)
self.frame1.grid_rowconfigure(0, weight=1)
self.frame1.grid_columnconfigure((0, 4), weight=1)
# 年月選択ボタン
self.navi_back = tk.Button(self.frame1, text=f'<', relief=tk.FLAT,
command=lambda: self.month_change('left'))
self.navi_back.grid(row=0, column=0, padx=(140, 10), pady=10, sticky=tk.E)
self.navi = [tk.Label(self.frame1, text=f'{self.yml[i]}') for i in range(len(self.yml))]
[self.navi[i].grid(row=0, column=i+1, pady=10) for i in range(len(self.yml))]
self.navi_next = tk.Button(self.frame1, text=f'>', relief=tk.FLAT,
command=lambda: self.month_change('right'))
self.navi_next.grid(row=0, column=4, padx=(10, 140), pady=10, sticky=tk.W)
# カレンダー表示フレーム
self.frame2 = tk.Frame(self.master)
self.frame2.grid(row=1, column=0, padx=10, pady=(0, 10), sticky=tk.NSEW)
self.frame2.grid_rowconfigure(tuple(range(7)), weight=1)
self.frame2.grid_columnconfigure(tuple(range(7)), weight=1)
# 曜日表示
self.youbi = [tk.Label(self.frame2, text=f'{"日月火水木金土"[i]}') for i in range(7)]
[self.youbi[i].grid(row=0, column=i, padx=3, pady=5, sticky=tk.NSEW) for i in range(7)]
self.youbi[0].configure(fg='crimson')
self.youbi[6].configure(fg='navy')
# カレンダー表示
self.calender = []
for i in range(self.eom):
tmp = tk.Button(self.frame2, text=f'{i+1}', relief=tk.GROOVE,
command=partial(self.click_date, i+1))
tmp.grid(row=(self.bom + i)//7+1, column=(self.bom + i)%7, padx=3, pady=5, sticky=tk.NSEW)
if (self.bom + i)%7 == 6:
tmp.configure(fg='navy')
elif not jpbizday.is_bizday(datetime.date(self.now_year, self.now_month, i+1)):
tmp.configure(fg='crimson')
self.calender.append(tmp)
# 行数固定用NULLボタン
tmp = tk.Button(self.frame2, text=' ', relief=tk.FLAT)
tmp.grid(row=6, column=6, padx=3, pady=5, sticky=tk.NSEW)
# 年月変更処理
def month_change(self, direction):
if direction == 'left':
self.now_month -= 1
elif direction == 'right':
self.now_month += 1
if self.now_month == 0:
self.now_year -= 1
self.now_month = 12
elif self.now_month == 13:
self.now_year += 1
self.now_month = 1
# 年月変更
self.days_setting()
# 画面更新
self.create_widgets()
# 年月設定処理
def days_setting(self):
# 1日の曜日(beginning of the month)
self.bom = datetime.datetime(self.now_year, self.now_month, 1).isoweekday()
# 月末の日付(end of month)
self.eom = calendar.monthrange(self.now_year, self.now_month)[1]
# 年月表示用の配列(year, month, list)
self.yml = [self.now_year, ' / ', self.now_month]
# 日付クリック時の処理
def click_date(self, date):
mb.showinfo('click', f'{self.now_year}/{self.now_month}/{date}')
if __name__ == '__main__':
root = tk.Tk()
app = Application(master = root)
app.mainloop()
最後に
マインスイーパーに比べるとあまりすっきり感のないコードになってしまいました。
やはりフレーム、年月選択、曜日表示などループ以外のウィジェットが増えていくと煩雑化します。