Python の学習を始めたばかりで、簡単なアプリケーションを 1 つまたは 2 つ作成したことがあるかもしれません。おめでとう!しかし、今何ですか?では、ピカピカの新しい Python アプリと対話するためのグラフィカル ユーザー インターフェイス ("GUI") を構築するのはどうでしょうか?
Python で GUI アプリケーションを構築するには、 PyQtやwxPythonなど、いくつかのオプションがあります。ただし、このガイドではTkinterについて紹介します。
「Tk インターフェイス」の略であるTkinterは、GUI を構築するための Python の標準であり、 Python 標準ライブラリに含まれています。これは、さまざまなプログラミング言語でグラフィカル インターフェイスを構築するために使用できる GUIウィジェットの無料のオープン ソース ライブラリであるTk GUI ツールキットへのバインディングです。
このチュートリアルでは、ユーザーが選択したタイムゾーンで現地時間を表示する基本的な GUI アプリケーションの設計について説明します。この手順では、アプリケーションを段階的に構築し、GUI 要素のレイアウト、ユーザー入力のキャプチャ、GUI 要素のコールバック メソッドへのバインドなど、 Tkinterを操作する際の重要な概念のいくつかについて説明します。
このガイドを完了するには、次のものが必要です。
pip
。pytz
タイムゾーン ライブラリをインストールしました。ライブラリはpip
を使用してインストールできます。
pip install pytz
このガイドでは、ルート ウィンドウとメイン ウィンドウという用語を同じ意味で使用します。
timezone.py
という名前の新しい Python アプリケーションを作成し、次のimport
ステートメントを追加してTkinter
、 datetime
、およびpytz
モジュールをインポートします。
import tkinter as tk import datetime import pytz
このガイドには、 pytz
でサポートされているタイムゾーンのごく一部である米国のタイムゾーンのセットが組み込まれています。アプリケーションの機能は、追加のpytz
タイムゾーン名を追加することで拡張できます。次のコマンドを実行すると、 pytz
で使用できるタイムゾーンの完全なリストを出力できます。
print(pytz.all_timezones)
pytz
を介して利用可能な米国のタイムゾーンのセットは、リストとして指定されます。
import tkinter as tk import datetime import pytz timezones = ["US/Alaska", "US/Aleutian", "US/Arizona", "US/Central", "US/East-Indiana", "US/Eastern", "US/Hawaii", "US/Indiana-Starke", "US/Michigan", "US/Mountain", "US/Pacific", "US/Samoa"]
Tk
クラスをインスタンス化すると、タイムゾーン アプリケーションの GUI のメイン ウィンドウとして機能するルート ウィンドウが作成されます。
import tkinter as tk import datetime import pytz timezones = ["US/Alaska", "US/Aleutian", "US/Arizona", "US/Central", "US/East-Indiana", "US/Eastern", "US/Hawaii", "US/Indiana-Starke", "US/Michigan", "US/Mountain", "US/Pacific", "US/Samoa"] root = tk.Tk()
この手順では、ルート ウィンドウ、特にそのタイトル、ジオメトリ、およびサイズ変更可能性を構成します。
ウィンドウのタイトルはtitle
メソッドを使用して設定されます。
import tkinter as tk import datetime import pytz timezones = ["US/Alaska", "US/Aleutian", "US/Arizona", "US/Central", "US/East-Indiana", "US/Eastern", "US/Hawaii", "US/Indiana-Starke", "US/Michigan", "US/Mountain", "US/Pacific", "US/Samoa"] root = tk.Tk() root.title("Simple Timezone Application")
ウィンドウの幅と高さの値 (ピクセル単位) を変数に割り当てて、コードを理解しやすくすることができます。
import tkinter as tk import datetime import pytz timezones = ["US/Alaska", "US/Aleutian", "US/Arizona", "US/Central", "US/East-Indiana", "US/Eastern", "US/Hawaii", "US/Indiana-Starke", "US/Michigan", "US/Mountain", "US/Pacific", "US/Samoa"] root = tk.Tk() root.title("Simple Timezone Application") window_width = 450 window_height = 175
メイン ウィンドウは画面のどこにでも配置できます。たとえば、中央、左上隅などです。中央に配置されたウィンドウは見栄えがよく、ルート ウィンドウのwinfo_screenwidth()
を使用してメイン ウィンドウの中央位置を決定できます。 winfo_screenwidth()
およびwinfo_screenheight()
メソッドといくつかの簡単な計算。これら 2 つのメソッドは、メイン ウィンドウを中央に配置するための適切な (x,y) 座標を計算するために使用される画面の幅と高さを返します。ウィンドウの幅と高さと同様に、中心位置の値も変数に割り当てて、コードを読みやすくすることができます。
import tkinter as tk import datetime import pytz timezones = ["US/Alaska", "US/Aleutian", "US/Arizona", "US/Central", "US/East-Indiana", "US/Eastern", "US/Hawaii", "US/Indiana-Starke", "US/Michigan", "US/Mountain", "US/Pacific", "US/Samoa"] root = tk.Tk() root.title("Simple Timezone Application") window_width = 450 window_height = 175 screen_width = root.winfo_screenwidth() screen_height = root.winfo_screenheight() center_x = int((screen_width - window_width)/2) center_y = int((screen_height - window_height)/2)
center_x
とcenter_y
の値もピクセルで表され、両方の計算値が整数になるようにint
が使用されることに注意してください。
メイン ウィンドウのサイズと位置を指定するroot
ウィンドウ ジオメトリは、ルート ウィンドウのgeometry
メソッドを使用して設定されます。簡単にするために、実行時にジオメトリ変数の式を補間する、書式設定された文字列リテラルまたはf-stringを使用できます。次のコード ブロックに従って、 f-stringリテラルはgeometry
メソッドにパラメーターとして渡されます。
import tkinter as tk import datetime import pytz timezones = ["US/Alaska", "US/Aleutian", "US/Arizona", "US/Central", "US/East-Indiana", "US/Eastern", "US/Hawaii", "US/Indiana-Starke", "US/Michigan", "US/Mountain", "US/Pacific", "US/Samoa"] root = tk.Tk() root.title("Simple Timezone Application") window_width = 450 window_height = 175 screen_width = root.winfo_screenwidth() screen_height = root.winfo_screenheight() center_x = int((screen_width - window_width)/2) center_y = int((screen_height - window_height)/2) root.geometry(f"{window_width}x{window_height}+{center_x}+{center_y}")
x 軸と y 軸に沿ったルート ウィンドウのサイズ変更可能性は、ルート ウィンドウのresizable
なメソッドを介して設定できます。 resizable
なメソッドは、 height
とwidth
のパラメーターをこの順序で受け入れます。いずれかのパラメーターのTrue
またはゼロ以外の値は、メイン ウィンドウが関連付けられた軸に沿ってサイズ変更可能であることを指定します。いずれかのパラメーターのFalse
または0
の値は、メイン ウィンドウが指定された軸に沿ってサイズ変更できないことを指定します。タイマー アプリケーションは、高さと幅の両方にFalse
の値を使用して、メイン ウィンドウのサイズが変更されないようにします。
import tkinter as tk import datetime import pytz timezones = ["US/Alaska", "US/Aleutian", "US/Arizona", "US/Central", "US/East-Indiana", "US/Eastern", "US/Hawaii", "US/Indiana-Starke", "US/Michigan", "US/Mountain", "US/Pacific", "US/Samoa"] root = tk.Tk() root.title("Simple Timezone Application") window_width = 450 window_height = 175 screen_width = root.winfo_screenwidth() screen_height = root.winfo_screenheight() center_x = int((screen_width - window_width)/2) center_y = int((screen_height - window_height)/2) root.geometry(f"{window_width}x{window_height}+{center_x}+{center_y}") root.resizable(False, False)
ウィジェットは、ジオメトリ マネージャーを使用してさまざまな方法でメイン ウィンドウの上に配置できます。通常、ウィジェットは次の 3 つの方法で配置できます。
pack()
メソッドを使用してパックされます。 pack()
ジオメトリ マネージャーは、ルート ウィンドウまたは親ウィジェットに追加される前に、ウィジェットをブロックに編成します。パッキングについて考える不完全だがおそらく役立つ方法は、食料品を買い物袋に追加することを考えることです。アイテムは、必ずしもバッグ内の事前定義された場所に追加されるとは限りません。むしろ、すべてのアイテムがバッグに入れられるまで、使用可能なスペースを使用して、次々と梱包されます。 pack()
ジオメトリ マネージャも同様に機能します。
place()
メソッドを使用して配置されます。 place()
ジオメトリ マネージャーは、ウィジェットをルート ウィンドウまたは親ウィジェットの特定の事前定義された位置に配置します。このジオメトリ マネージャーは、正確な GUI レイアウトを構築するときに明らかに役立ちます。
grid()
メソッドを使用してグリッドとして配置します。グリッドは、2 次元の行/列テーブルです。ウィジェットを配置する特定の行と列を指定して、ウィジェットをグリッドに追加します。グリッドは、ルート ウィンドウのcolumnconfigure
およびrowconfigure
メソッドを使用してセットアップされます。これらの各メソッドには、 index
とweight
の属性があります。 index
属性は、開始基準0
を使用して列または行の位置を指定します。 weight
属性は、他の列に対する特定の列または行のサイズを指定します。たとえば、列 0の重みが1
で、列 1の重みが3
の場合、列 1は列 0の 3 倍の大きさになります。
グリッドは要素を隣り合わせに配置する場合に便利で、実装も比較的簡単です。タイムゾーン アプリケーションは、4 つの等しい列に分割されたメイン ウィンドウ グリッドを使用します。
import tkinter as tk import datetime import pytz timezones = ["US/Alaska", "US/Aleutian", "US/Arizona", "US/Central", "US/East-Indiana", "US/Eastern", "US/Hawaii", "US/Indiana-Starke", "US/Michigan", "US/Mountain", "US/Pacific", "US/Samoa"] root = tk.Tk() root.title("Simple Timezone Application") window_width = 450 window_height = 175 screen_width = root.winfo_screenwidth() screen_height = root.winfo_screenheight() center_x = int((screen_width - window_width)/2) center_y = int((screen_height - window_height)/2) root.geometry(f"{window_width}x{window_height}+{center_x}+{center_y}") root.resizable(False, False) root.columnconfigure(0, weight=1) root.columnconfigure(1, weight=1) root.columnconfigure(2, weight=1) root.columnconfigure(3, weight=1)
このステップでは、ステップ 4 で定義したメイン ウィンドウ グリッドにウィジェットを追加します。タイムゾーン アプリケーションは 3 つのTKinterウィジェットを使用します。
Label
Listbox
Button
Tkinter のLabel
ウィジェットとButton
ウィジェットは、その名前の通りです。 Label
ウィジェットを使用すると、プログラマはテキスト (つまり、ラベル) を表示できますButton
ウィジェットは、ボタンを表示するために使用されます。 Listbox
ウィジェットは、オプションのリストから値を選択するために使用されます。
もちろん、 SpinBox
、 Entry
、 Message
ウィジェットなど、上記の 3 つ以外のウィジェットもあります。正式なTk コマンドのドキュメントは、Tk ツールキットで利用できるウィジェットについて詳しく知るのに役立つリソースです。
各ウィジェット クラスのインスタンスは、GUI デザインで使用される特定のウィジェットに対して作成されます。タイムゾーン アプリケーションは、2 つのLabel
ウィジェット、1 つのListbox
ウィジェット、および 1 つのButton
ウィジェットの 4 つのウィジェット インスタンスを使用します。
import tkinter as tk import datetime import pytz timezones = ["US/Alaska", "US/Aleutian", "US/Arizona", "US/Central", "US/East-Indiana", "US/Eastern", "US/Hawaii", "US/Indiana-Starke", "US/Michigan", "US/Mountain", "US/Pacific", "US/Samoa"] root = tk.Tk() root.title("Simple Timezone Application") window_width = 450 window_height = 175 screen_width = root.winfo_screenwidth() screen_height = root.winfo_screenheight() center_x = int((screen_width - window_width)/2) center_y = int((screen_height - window_height)/2) root.geometry(f"{window_width}x{window_height}+{center_x}+{center_y}") root.resizable(False, False) root.columnconfigure(0, weight=1) root.columnconfigure(1, weight=1) root.columnconfigure(2, weight=1) root.columnconfigure(3, weight=1) # Instance of Label widget class for selection prompt. select_timezone_label = tk.Label(root, text="Please select a timezone.") # Instance of Listbox class for selection of timezone from list. list_var = tk.Variable(value=timezones) select_timezone_listbox = tk.Listbox(root, listvariable=list_var, height=1) # Instance of Button class to get the local time in the selected timezone. select_timezone_button = tk.Button(root, text="Get Time") # Second instance of the Label class to display the local time in the selected timezone. time_label = tk.Label(root, text="")
上記のコード ブロックに見られるように、各ウィジェット インスタンスはroot
ウィンドウに「接続」されています。 Listbox
ウィジェットには、特別な Tkinter Variable()
クラスのインスタンス化も必要です。これは、ユーザーがListbox
のlistvariable
属性を介して選択できるタイムゾーン オプションのリストをウィジェットに提供するために使用されます。各Label
ウィジェットによって表示されるテキストは、 text
属性を使用して構成できます。 time_label
のテキスト値は、ユーザーが選択したタイムゾーンの時間を「取得」するたびに動的に設定されるため、空白のままにします。
ステップ 5a で作成されたウィジェット インスタンスは、 grid()
メソッドを使用して、ステップ 4 で定義されたグリッドに配置できます。タイムゾーン アプリケーションは、次のgrid()
メソッド属性を使用してレイアウトを定義します。
column
: 0
基準を使用してウィジェットが配置される特定の列を指定します。
row
: 0
ベースを使用してウィジェットが配置される特定の行を指定します。
columnspan
: ウィジェットが指定された数の列にまたがるように指定します。たとえば、値がcolumnspan=3
のウィジェットは、ウィジェット自体が 3 列より小さい場合でも、3 列にまたがります。
sticky
: Tkinter のデフォルトの動作は、セルの水平方向および垂直方向の中央 (つまり、特定の行/列の位置) にウィジェットを配置することです。このデフォルトの動作は、コンパスのような値 ( NW
、 N
、 NE
、 W
、 E
、 SW
、 S
、 SE
など) を使用するsticky
属性を使用してオーバーライドでき、ウィジェットのセル内の特定の位置にウィジェットを配置できます。たとえば、 sticky=tK.W
は、ウィジェットをグリッド セルの西隅に配置するように指定します。同様に、 sticky=tK.E
は、ウィジェットをグリッド セルの東隅に配置する必要があることを指定します。
padx
、 pady
: padx
およびpady
属性は、ピクセルで指定された値でそれぞれ x 軸および y 軸のパディングを追加するために使用されます。当然のことながら、パディングは、ウィジェットがルート ウィンドウや他のウィジェットの端に直接「ぶつかる」ことがないように、よりプロフェッショナルな外観の GUI を提供できます。
import tkinter as tk import datetime import pytz timezones = ["US/Alaska", "US/Aleutian", "US/Arizona", "US/Central", "US/East-Indiana", "US/Eastern", "US/Hawaii", "US/Indiana-Starke", "US/Michigan", "US/Mountain", "US/Pacific", "US/Samoa"] root = tk.Tk() root.title("Simple Timezone Application") window_width = 450 window_height = 175 screen_width = root.winfo_screenwidth() screen_height = root.winfo_screenheight() center_x = int((screen_width - window_width)/2) center_y = int((screen_height - window_height)/2) root.geometry(f"{window_width}x{window_height}+{center_x}+{center_y}") root.resizable(False, False) root.columnconfigure(0, weight=1) root.columnconfigure(1, weight=1) root.columnconfigure(2, weight=1) root.columnconfigure(3, weight=1) # Instance of Label widget class for selection prompt. select_timezone_label = tk.Label(root, text="Please select a timezone.") # Instance of Listbox class for selection of timezone from list. list_var = tk.Variable(value=timezones) select_timezone_listbox = tk.Listbox(root, listvariable=list_var, height=1) # Instance of Button class to get the local time in the selected timezone. select_timezone_button = tk.Button(root, text="Get Time") # Second instance of the Label class to display the local time in the selected timezone. time_label = tk.Label(root, text="") # Place widgets on grid. select_timezone_label.grid(column=0, row=0, columnspan=4, sticky=tk.W, padx=10, pady=10) select_timezone_listbox.grid(column=0, row=1, columnspan=3, sticky=tk.EW, padx=10, pady=10) select_timezone_button.grid(column=4, row=1, sticky=tk.E, padx=10, pady=10) time_label.grid(column=0, row=4, columnspan=4, sticky=tk.W, padx=10, pady=10)
手順 5 で作成したselect_timezone_button
ボタンをユーザーがクリックしたときにイベントを処理するには、コールバック メソッドを定義する必要があります。
コールバック ロジックを定義する前に、最終的にコールバック コードを含むメソッド名にボタンをバインドすることをお勧めします。 bind()
メソッドをlambda
関数と組み合わせて使用して、 select_timezone_button
を指定されたコールバック メソッドにバインドできます。また、 lambda
関数を使用してselect_timezone_listbox
およびtime_label
ウィジェットへの参照をコールバック パラメータとして渡すことにも注意してください。 select_timezone_listbox
とtime_label
はグローバル スコープ内にあるため、これらのコールバック パラメータは実際には必要ありません。ただし、引数をコールバック関数に渡す方法を示すことは間違いなく役に立ちます。
import tkinter as tk import datetime import pytz timezones = ["US/Alaska", "US/Aleutian", "US/Arizona", "US/Central", "US/East-Indiana", "US/Eastern", "US/Hawaii", "US/Indiana-Starke", "US/Michigan", "US/Mountain", "US/Pacific", "US/Samoa"] root = tk.Tk() root.title("Simple Timezone Application") window_width = 450 window_height = 175 screen_width = root.winfo_screenwidth() screen_height = root.winfo_screenheight() center_x = int((screen_width - window_width)/2) center_y = int((screen_height - window_height)/2) root.geometry(f"{window_width}x{window_height}+{center_x}+{center_y}") root.resizable(False, False) root.columnconfigure(0, weight=1) root.columnconfigure(1, weight=1) root.columnconfigure(2, weight=1) root.columnconfigure(3, weight=1) # Instance of Label widget class for selection prompt. select_timezone_label = tk.Label(root, text="Please select a timezone.") # Instance of Listbox class for selection of timezone from list. list_var = tk.Variable(value=timezones) select_timezone_listbox = tk.Listbox(root, listvariable=list_var, height=1) # Instance of Button class to get the local time in the selected timezone. select_timezone_button = tk.Button(root, text="Get Time") # Second instance of the Label class to display the local time in the selected timezone. time_label = tk.Label(root, text="") # Place widgets on grid. select_timezone_label.grid(column=0, row=0, columnspan=4, sticky=tk.W, padx=10, pady=10) select_timezone_listbox.grid(column=0, row=1, columnspan=3, sticky=tk.EW, padx=10, pady=10) select_timezone_button.grid(column=4, row=1, sticky=tk.E, padx=10, pady=10) time_label.grid(column=0, row=4, columnspan=4, sticky=tk.W, padx=10, pady=10) select_timezone_button.bind("<Button>", lambda e, args=[select_timezone_listbox, time_label]: get_timezone_time(e, args))
ボタン クリック イベントを処理するためのコールバック ロジックを以下に定義します。
def get_timezone_time(e, args): select_timezone_listbox = args[0] time_label = args[1] selection_index = select_timezone_listbox.curselection() selected_timezone = select_timezone_listbox.get(selection_index) now_time = datetime.datetime.now() tz_time = now_time.astimezone(pytz.timezone(selected_timezone)) tz_formatted = tz_time.strftime("%H:%M:%S") time_label.configure({"text": f"The time in {selected_timezone} is {tz_formatted}."}) time_label.update()
curselection()
およびget()
メソッドは、ユーザーが選択したタイムゾーンをselect_timezone_listbox
ウィジェットへの参照から取得するために使用されます。次に、ユーザーの現在の時刻が、選択したタイムゾーンの時刻に変換されます。最後に、 configure
メソッドを使用して、 time_label
への参照のtext
属性を、選択したタイムゾーンの現地時間に変更します。 update()
メソッドは、 time_label
ウィジェットを新しいテキスト値で更新するよう「強制」するために使用されることに注意してください。
ルート ウィンドウのmainloop()
メソッドは、コードの最後の行として適用されます。 mainloop()
メソッドは、ユーザーが終了するまで GUI を無限ループで実行します。
完成したコードは次のとおりです。
import tkinter as tk import datetime import pytz timezones = ["US/Alaska", "US/Aleutian", "US/Arizona", "US/Central", "US/East-Indiana", "US/Eastern", "US/Hawaii", "US/Indiana-Starke", "US/Michigan", "US/Mountain", "US/Pacific", "US/Samoa"] def get_timezone_time(e, args): select_timezone_listbox = args[0] time_label = args[1] selection_index = select_timezone_listbox.curselection() selected_timezone = select_timezone_listbox.get(selection_index) now_time = datetime.datetime.now() tz_time = now_time.astimezone(pytz.timezone(selected_timezone)) tz_formatted = tz_time.strftime("%H:%M:%S") time_label.configure({"text": f"The time in {selected_timezone} is {tz_formatted}."}) time_label.update() root = tk.Tk() root.title("Simple Timezone Application") window_width = 450 window_height = 175 screen_width = root.winfo_screenwidth() screen_height = root.winfo_screenheight() center_x = int((screen_width - window_width)/2) center_y = int((screen_height - window_height)/2) root.geometry(f"{window_width}x{window_height}+{center_x}+{center_y}") root.resizable(False, False) root.columnconfigure(0, weight=1) root.columnconfigure(1, weight=1) root.columnconfigure(2, weight=1) root.columnconfigure(3, weight=1) # Instance of Label widget class for selection prompt. select_timezone_label = tk.Label(root, text="Please select a timezone.") # Instance of Listbox class for selection of timezone from list. list_var = tk.Variable(value=timezones) select_timezone_listbox = tk.Listbox(root, listvariable=list_var, height=1) # Instance of Button class to get the local time in the selected timezone. select_timezone_button = tk.Button(root, text="Get Time") # Second instance of the Label class to display the local time in the selected timezone. time_label = tk.Label(root, text="") # Place widgets on grid. select_timezone_label.grid(column=0, row=0, columnspan=4, sticky=tk.W, padx=10, pady=10) select_timezone_listbox.grid(column=0, row=1, columnspan=3, sticky=tk.EW, padx=10, pady=10) select_timezone_button.grid(column=4, row=1, sticky=tk.E, padx=10, pady=10) time_label.grid(column=0, row=4, columnspan=4, sticky=tk.W, padx=10, pady=10) # Bind button to callback. select_timezone_button.bind("<Button>", lambda e, args=[select_timezone_listbox, time_label]: get_timezone_time(e, args)) root.mainloop()
アプリケーションを起動すると、GUI は次のようになります。
アプリケーションを使用するには、リスト ボックスをクリックし、キーボードの上下カーソル キーを使用してタイムゾーン オプションをスクロールします。 [時刻を取得] ボタンをクリックして、選択したタイムゾーンで現在の時刻を表示します。
Tkinterを使用した最初の Python GUI アプリケーションの作成、おめでとうございます!はじめにで述べたように、このガイドはいくつかの基本的な概念を紹介するように設計されています。前述のPython 標準ライブラリ ドキュメントとTk コマンド ドキュメントリファレンスは、より高度な Tkinter の特徴と機能について学習するのに役立つ 2 つの優れたリソースです。
Tkinter GUI アプリケーションは、非ネイティブなルック アンド フィールを持っていると批判されることがあります。それは本当かもしれません。しかし、ツールキット ウィジェットは高度に構成可能であり、Tkinter GUI アプリケーションは、外部の Python パッケージをインストールする必要なく比較的迅速に構築できます。
正式なドキュメント以外にも、Tkinter を使用してより洗練された GUI アプリケーションを構築する方法を学ぶための無数のチュートリアルがインターネット経由で入手できます。