LoginSignup
0
0

More than 1 year has passed since last update.

[Python][tkinter] 1次元配列でカレンダー表示

Last updated at Posted at 2023-02-15

作ったプログラムの備忘録

はじめに

1次元配列でgrid表示させる方法で、カレンダー表示させてみました。

日付ウィジェットの配置は単純化できますが、日祝土曜日の色変化やヘッダー部分など含めると、結果的にウィジェット配置のコードもそこそこ長くなってしまったなと言う感じです。

978FBBF0-9043-4DB1-AE36-F02546C489B7.png
43DD3293-F66C-482A-852B-A1D74C490979.png

動作テスト環境

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.bomdef 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()

最後に

マインスイーパーに比べるとあまりすっきり感のないコードになってしまいました。
やはりフレーム、年月選択、曜日表示などループ以外のウィジェットが増えていくと煩雑化します。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0