Abstract
pythonで簡単なGUIを作成する機会があり、その際に日付の入力欄を作る必要があった。要件としては、入力欄は基本的には手打ちだが、カレンダー選択による自動入力機能を付けてほしいとうことだった。Webのノリで簡単にできるだろうと高をくくっていたら意外とはまってしまったので、誰の役に立つかわからないが残しておくことにする。
実装
calenderdialog.py
import tkinter
from tkinter.simpledialog import Dialog
from tkcalendar import Calendar
class CalenderDialog(Dialog):
date: str
def __init__(self, master: tkinter.Tk, title=None) -> None:
self.date = ""
super().__init__(parent=master, title=title)
#//Override
def body(self, master) -> None:
self.calendar = Calendar(master, showweeknumbers=False, date_pattern="yyyy/mm/dd")
self.calendar.grid(sticky="w", row=0, column=0)
#//Override
def apply(self) -> None:
self.date = self.calendar.get_date()
print(self.date)
def get_date(self) -> str:
return self.date
いろいろ方法はあると思うが、既存のダイアログをカスタマイズして、カレンダーから情報を返す方法が簡単そうだったので今回はこの方法をとる。具体的にはtkinter.simpledialog.Dialog
を継承し、下記メンバを2つオーバライドすることで簡単に実現できる。
body()
ダイアログの本体を表示するメソッド
apply()
OKボタンが押されたときに実行するメソッド
body()
でカレンダーを表示させ、OKボタンをトリガーに日付の値をself.date
へ格納する。
公式いわくOKやCancelの表示が気に食わないひとはbuttonbox()
をオーバーライドしてカスタマイズしてとのこと。
テスト
test.py
#//自作したDialog
from calenderdialog import CalenderDialog
import tkinter
from tkinter import Frame
from tkinter import Label
from tkinter import Entry
from tkinter import Button
class Test:
def __init__(self):
self.root = tkinter.Tk()
self.root.geometry("200x200")
fream = Frame(self.root, bd=4, relief="groove")
label = Label(fream, text="Date")
label.grid(padx=2, sticky="w", row=0, column=0)
self.entry = Entry(fream, width=20)
self.entry.grid(sticky="w", row=1, column=0)
button = Button(fream,text="get",width=4,command=self.get_date)
button.grid(sticky="w", row=1, column=1)
fream.pack()
def get_date(self) -> None:
dialog = CalenderDialog(self.root, title="calendar")
date = dialog.get_date()
if date != "":
self.entry.delete(0, tkinter.END)
self.entry.insert(0,date)
def run(self):
self.root.mainloop()
if __name__ == "__main__":
test = Test()
test.run()
実行可能なテストコードを示す。
手打ち入力とカレンダー入力に対応した入力欄を作ることができた。