環境
- Windows 10
- Python 3.10.1
- VSCode
Tkinterとは?
PythonでGUIを組むことのできるツールキット
GUI化することにより、Pythonスクリプトファイルをコンソール等から直接実行しなくてもよくなります。
動作イメージ
下図のような簡単なランチャーを作成してみたいと思います。ボタンをクリックすると任意のpythonプログラムが実行されます
事前準備
Tkinterは通常はPythonの標準ライブラリなので、特にインストール等は不要です
基本的な使用方法
GUIウインドウの作成
- tkinterをインポートして、オブジェクトを作成
- GUIのウインドウタイトルの設定
- ウインドウサイズ(横x縦)の設定
import tkinter
root = tkinter.Tk()
root.title("Window Title")
root.geometry("400x300")
-----具体的な処理の内容はこの中に記載する
root.mainloop()
具体的な実行内容の処理はroot = Tkinter.Tk()とroot.mainloop()の間に記載します
上記のプログラムを実行すると、400px * 300pxのウインドウが表示されます
ラベルの作成
- ラベルを作成し、今日の日付を引数として渡して画面上に表示します
- tkinter.Label(text=)に引数としてラベルに表示する値を指定します
- 部品.pack()とすることで、ウィンドウ上に部品を配置することが可能です
import datetime
・・・割愛
root.geometry("400x300")
today = datetime.date.today()
# ラベル
label = tkinter.Label(text=today)
label.pack()
root.mainloop()
今日の日付は、datetimeモジュールで簡単に生成することが可能です
上記のプログラムを実行すると、ウインドウ上に日付のラベルが表示されます
ラベルの配置
上記で作成したラベルをpackメソッドでウインドウの右上に配置します
部品の配置のためのメソッドには、大きく分けてpack, place, gridの3パターンがあります
- packメソッドのanchor引数にtkinter.NEと指定することで、部品を右上に配置することが可能です
- padxで横方向のpaddingを、padyで縦方向のpaddingを指定できます
# ラベル
label = tkinter.Label(text=today)
label.pack(anchor=tkinter.NE, padx=10, pady=5)
anchor一覧
項目 | 内容 |
中央(デフォルト) | |
Tk.W | 左よせ |
Tk.E | 右よせ |
Tk.N | 上よせ |
Tk.S | 下よせ |
Tk.NW | 左上 |
Tk.SW | 左下 |
右上 | |
右下 |
ここまでで、GUIが以下のようになります
import datetime
import tkinter
root = tkinter.Tk()
root.title("Window Title")
root.geometry("700x300")
today = datetime.date.today()
# ラベル
label = tkinter.Label(text=today)
label.pack(anchor=tkinter.NE, padx=10, pady=5)
root.mainloop()
ボタンの作成と配置
- tkinter.Button()でボタンが作成できます
- ボタンオブジェクトは、キー名を指定していろいろな情報を設定できます(ボタン名やクリック時に実行する関数 ※いったん適当に設定)
- grid(配置する列, 配置する行)で該当の部品を配置する場所を指定し、stickyを指定してウィンドウサイズに応じて伸縮するようにします
部品の均等配置には、gridを使用すると実装しやすいです
stickyの設定値
stickyを使用すると、スペースに余裕がある場合、どこに配置するか・どのように引き伸ばすかを指定できます
項目 | 内容 |
中央 | |
tk.W | 左寄せ |
tk.E | 右寄せ |
tk.N | 上寄せ |
tk.S | 下寄せ |
tk.NW | 左上 |
tk.SW | 左下 |
右上 | |
右下 |
各行・列の引き延ばし設定
- 上記のstickyで部品自体の引き延ばしの設定と合わせて、ルート要素(ウィンドウ)に対しても設定を行う必要があります
- 今回のランチャーでは、3*3の構成にしたいので、以下のように設定します
# 各行・列の引き伸ばし設定
root.grid_columnconfigure(0, weight=1)
root.grid_columnconfigure(1, weight=1)
root.grid_columnconfigure(2, weight=1)
root.grid_rowconfigure(0, weight=0)
root.grid_rowconfigure(1, weight=1)
root.grid_rowconfigure(2, weight=1)
weightを使用することにより、余白を配分するときの割合を数値で指定することができます(重みづけ)
ここまでで、GUIが以下のようになります
import datetime
import tkinter
root = tkinter.Tk()
root.title("Launcher")
root.geometry("400x200")
frame = tkinter.Frame(root, bg="red")
today = datetime.date.today()
# ラベル
label = tkinter.Label(text=today)
label.grid(column=0, row=0, sticky=tkinter.E, columnspan=3)
# ボタン *6
btn1 = tkinter.Button()
btn1["text"] = "勤怠"
btn1["command"] = root.destroy
btn1.grid(column=0, row=1, sticky="NSEW")
btn2 = tkinter.Button()
btn2["text"] = "②"
btn2["command"] = root.destroy
btn2.grid(column=1, row=1, sticky="NSEW")
btn3 = tkinter.Button()
btn3["text"] = "③"
btn3["command"] = root.destroy
btn3.grid(column=2, row=1, sticky="NSEW")
btn4 = tkinter.Button()
btn4["text"] = "④"
btn4["command"] = root.destroy
btn4.grid(column=0, row=2, sticky="NSEW")
btn5 = tkinter.Button()
btn5["text"] = "⑤"
btn5["command"] = root.destroy
btn5.grid(column=1, row=2, sticky="NSEW")
btn6 = tkinter.Button()
btn6["text"] = "⑥"
btn6["command"] = root.destroy
btn6.grid(column=2, row=2, sticky="NSEW")
# 各列の引き伸ばし設定
root.grid_columnconfigure(0, weight=1)
root.grid_columnconfigure(1, weight=1)
root.grid_columnconfigure(2, weight=1)
root.grid_rowconfigure(0, weight=0)
root.grid_rowconfigure(1, weight=1)
root.grid_rowconfigure(2, weight=1)
root.mainloop()
ボタンのクリックイベント
- ["command"]のキーにpythonで定義した関数やメソッドを代入することで、クリックイベントを設定できます
btn1 = tkinter.Button()
btn1["command"] = login.authenticate
def authenticate(): ...割愛
commandに指定する関数には()は不要です。付与してしまうとウィンドウを起動したタイミングで関数が実行されてしまいます。
これでクリックイベントが設定できましたのでひととおり完成です。
その他の部品
主なウィジェット一覧
ウィジェット名 | クラス名 | 概要 |
---|---|---|
フレーム | Frame | ウィジェットを格納する枠組みを作る |
ラベル | Label | 文字列やイメージを表示する |
メッセージ | Message | 複数行の文字列を表示する |
ボタン | Button | ボタンを作る |
ラジオボタン | Radiobutton | ラジオボタンを作る |
チェックボタン | Checkbutton | チェックボタンを作る |
リストボックス | Listbox | リストボックスを作る |
スクロールバー | Scrollbar | スクロールバーを作る |
スケール | Scale | スケールを作る |
エントリー | Entry | 1 行の文字列の入力と編集 |
メニュー | Menu | メニューを作る |
メニューボタン | Menubutton | メニューボタンを作る |
ビットマップ | Bitmap | ビットマップを作る |
キャンバス | Canvas | キャンバスを作る |
テキスト | Text | テキストの入力と編集 |
ラベルフレーム | LabelFrame | ラベル付きフレーム |
スピンボックス | Spinbox | スピンボックスを作る |
ペインウィンドウ | PanedWindow | ペインウィンドウを作る |
最終的には以下のようなコードになりました
今回は処理を順番に記述していくだけでしたが、メンテナンス性を向上させるためにも、専用のクラスを用意して責務を分けてコードを記述することをお勧めします。
packages\my_lanchar\main.py
import tkinter
from packages.my_lanchar.lanchar import Lanchar
from shared.Domain.i_widget import IWidget
root = tkinter.Tk()
root.title("Launcher")
root.geometry("400x200")
# パーツの設定
lanchar: IWidget = Lanchar(root=root).build()
root.mainloop()
shared\Domain\i_widget.py
from abc import *
class IWidget(metaclass=ABCMeta):
@abstractmethod
def build(self) -> None:
pass
@abstractmethod
def label(self):
pass
@abstractmethod
def btn(self):
pass
packages\my_lanchar\lanchar.py
import datetime
import tkinter
from typing import Callable, Optional
from packages.jobcan import login
from shared.Domain.i_widget import IWidget
class Lanchar(IWidget):
def __init__(self, root) -> None:
self.root = root
frame = tkinter.Frame(root)
# # 各列の引き伸ばし設定
root.grid_columnconfigure(0, weight=1)
root.grid_columnconfigure(1, weight=1)
root.grid_columnconfigure(2, weight=1)
root.grid_rowconfigure(0, weight=0)
root.grid_rowconfigure(1, weight=1)
root.grid_rowconfigure(2, weight=1)
def build(self):
label = self.label(datetime.date.today())
label.grid(column=0, row=0, sticky=tkinter.E, columnspan=3)
# ボタン
btn1 = self.btn("勤怠", login.authenticate)
btn1.grid(column=0, row=1, sticky="NSEW")
btn2 = self.btn("②")
btn2.grid(column=1, row=1, sticky="NSEW")
btn3 = self.btn("③")
btn3.grid(column=2, row=1, sticky="NSEW")
btn4 = self.btn("④")
btn4.grid(column=0, row=2, sticky="NSEW")
btn5 = self.btn("⑤")
btn5.grid(column=1, row=2, sticky="NSEW")
btn6 = self.btn("⑥")
btn6.grid(column=2, row=2, sticky="NSEW")
return self
def label(self, text: str):
return tkinter.Label(text=text)
def btn(self, text: str, command: Optional[Callable] = None):
btn = tkinter.Button()
btn["text"] = text
btn["command"] = command
return btn
Tkinterへの依存度を下げるために、インターフェースを作成し、それを実装する形で構築しています
まとめ
いかがでしたでしょうか。本記事では、Tkinterを使用してPythonでデスクトップアプリを作成する方法について紹介しています。Tkinterを使用すると簡単にデスクトップアプリを作成できますのでぜひ試してみてください。