【Python】カレンダーの作成方法

GUIアプリの勉強でTinkerを使用してカレンダーを作成しました。
# ウィンドウの作成

`tk.Tk()`でウィンドウ作成します。
`.title()`でタイトル、`geometry()`で画面サイズを指定します。

``` Python:

# -*- coding:utf-8 -*-

import jpbizday
import datetime
import calendar

class calWidget(tk.Frame):
    def __init__(self, master = None, cnf = {}, **kw):
    
        tk.Frame.__init__(self, master, cnf, **kw)

root = tk.Tk()
root.title("calendar")
root.geometry('600x400')

# 作成したウィジットを配置
widget = calWidget(root)
widget.pack()

root.mainloop()
```

# ウィジェットの配置
ウィンドウ内にウィジェットを配置します。
`ウィジェット.bind("<1>", 関数名)`で左クリックしたときの動作を追加します。
`ウィジェット.pack(side = "left")`でウィジェットを左に配置します。



``` Python:
# -*- coding:utf-8 -*-

import jpbizday
import datetime
import calendar

class calWidget(tk.Frame):
    def __init__(self, master = None, cnf = {}, **kw):
    
        tk.Frame.__init__(self, master, cnf, **kw)
        
        # 現在の日付を取得
        now = datetime.datetime.now()
        self.year = now.year
        self.month = now.month
        
        calTop = tk.Frame(self)
        calTop.pack(pady = 5)
        # 「＜」を表示
        self.previous = tk.Label(calTop, text = "<", font = ("",20))
        self.previous.bind("<1>", self.changeCal)
        self.previous.pack(side = tk.LEFT)
        # 今月を表示
        self.nowYear = tk.Label(calTop, text = self.year, font = ("",20))
        self.nowYear.pack(side = tk.LEFT)
        self.slash = tk.Label(frame_top, text = "/", font = ("",20))
        self.slash.pack(side = "left")
        self.nowMonth = tk.Label(calTop, text = self.month, font = ("",20))
        self.nowMonth.pack(side = tk.LEFT)
        # 「＞」を表示
        self.next = tk.Label(calTop, text = ">", font = ("",20))
        self.next.bind("<1>", self.changeCal)
        self.next.pack(side = tk.LEFT)


```
![スクリーンショット 2021-10-02 13.05.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431502/c0597b8e-1a89-ba7b-58e2-07b9ef68d80b.png)

# カレンダーのヘッダー

曜日のボタンを作成して、ヘッダーとして配置します。
配置するときに`grid`を使用しますが、
`column`は配置する列、`row`は配置する行
`padx`、`pady`は外側の隙間を指定します。


``` Python:

        calHeader = tk.Frame(self)
        calHeader.pack(pady = 5)
        # 日曜日
        self.sun = tk.Button(calHeader, text = "日", height = 2, width = 4, fg = "red", relief = "flat")
        self.sun.grid(column = 1, row = 1, padx = 10, pady = 5)
        # 月曜日
        self.mon = tk.Button(calHeader, text = "月", height = 2, width = 4, relief = "flat")
        self.mon.grid(column = 2, row = 1, padx = 10, pady = 5)
        # 火曜日
        self.tue = tk.Button(calHeader, text = "火", height = 2, width = 4, relief = "flat")
        self.tue.grid(column = 3, row = 1, padx = 10, pady = 5)
        # 水曜日
        self.wed = tk.Button(calHeader, text = "水", height = 2, width = 4, relief = "flat")
        self.wed.grid(column = 4 , row = 1, padx = 10, pady = 5)
        # 木曜日
        self.thu = tk.Button(calHeader, text = "木", height = 2, width = 4, relief = "flat")
        self.thu.grid(column = 5, row = 1, padx = 10, pady = 5)
        # 金曜日
        self.fri = tk.Button(calHeader, text = "金", height = 2, width = 4, relief = "flat")
        self.fri.grid(column = 6, row = 1, padx = 10, pady = 5)
        # 土曜日
        self.sat = tk.Button(calHeader, text = "土", height = 2, width = 4, fg = "blue", relief = "flat")
        self.sat.grid(column = 7, row = 1, padx = 10, pady = 5)

```

![スクリーンショット 2021-10-02 13.16.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431502/0869fd24-4ba5-294e-cc5d-ffb5ae29fef0.png)

# 日付の配置

日付を作成する関数を作成します。
`cal.monthdayscalendar(year, month)`で指定した年と月から
日付を取得します。

``` Python:
        # frame_calendar部分の作成
        self.calDate = tk.Frame(self)
        self.calDate.pack()

        # 日付部分を作成するメソッドの呼び出し
        self.createCal(self.year, self.month)

    # 日付を表示
    def createCal(self, year, month):
    
        # 初期化
        try:
            for key,item in self.day.items():
                item.destroy()
        except:
            pass
        
        cal = calendar.Calendar()
        cal.setfirstweekday(6)
        # 指定した年月のカレンダーをリストで返す
        days = cal.monthdayscalendar(year, month)
        days_count = sum(len(v) for v in days)

        self.day = {}
        # 日付
        for y in range(0, len(days)):
            for x in range(0, 7):
                # 平日：黒、土曜：青、祝日、日曜：赤
                if days[y][x] != 0:
                    date = days[y][x]
                    if jpbizday.is_bizday(datetime.date(nowYear, nowMonth, date)):
                        color = "black"

                    elif x == 6:
                        color = "blue"
                    else:
                        color = "red"
    
                    self.day[date] = tk.Button(self.frame_calendar, text = date, fg = color, height = 2, width = 4, relief = "flat")
                    self.day[date].bind("<Button-1>", callback)

                    self.day[date].grid(column = x, row = y, padx = 10, pady=5)

```
![スクリーンショット 2021-10-03 11.31.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431502/064536ad-a493-b9db-1e43-68d459879d2c.png)

# 別の月を表示させる
「＜」「＞」を押下したときに、カレンダーの表示を変更するようにします。
`self.month`、`self.year`を変更して、`createCal()`を呼び出すことで
カレンダーの表示を変更します。

``` Python:
    # 年月を変更
    def changeCal(self, event):
        if event.widget["text"] == "<":
            self.month -= 1
            # 1になった場合
            if self.month == 0:
                self.year -= 1
                self.month = 12
        else:
            self.month += 1
            # 13になった場合
            if self.month == 13:
                self.year +=1
                self.month =1

        # 年と月を変更
        self.nowYear["text"] = self.year
        self.nowMonth["text"] = self.month
        # 日付部分を作成する
        self.createCal(self.year, self.month)

```