Tkinter/ttkbootstrap(デスクトップGUI)
Tkinterとは
Tkinter は [[Python]] に標準で付属するGUIツールキットです。追加インストールなしにウィンドウ・ボタン・入力欄を作れるため、社内向けの小さなツールを配る用途で使われます。
import tkinter as tk
root = tk.Tk()
tk.Label(root, text="変換するファイルを選んでください").pack()
tk.Button(root, text="実行", command=lambda: run()).pack()
root.mainloop()
mainloop() はイベントループで、ここでウィンドウを保ちながらユーザーの操作を待ちます。この1行が返ってくるのはウィンドウを閉じたときです。
外観の古さが弱点でしたが、ttkbootstrap のようなテーマ集を被せると、コードをほぼ変えずに現代的な見た目にできます。
イベントループを止めない
GUI で最も多い不具合が「処理中に画面が固まる」です。原因は単純で、時間のかかる処理をイベントループと同じ流れで実行しているからです。
# 悪い例: 画面が固まる
def run():
convert_all_files() # 数十秒かかる
# 良い例: 別スレッドへ逃がす
def run():
threading.Thread(target=convert_all_files, daemon=True).start()
ただし、別スレッドから画面部品を直接触ってはいけません。進捗を反映したいときは、結果をキューに入れてメインスレッド側で定期的に取り出す(after で自分自身を再スケジュールする)構成にします。
| 症状 | 原因 | 対処 |
|---|---|---|
| ボタンを押すと固まる | 重い処理がイベントループを占有 | 別スレッドへ逃がす |
| 進捗が更新されない | 描画の機会が来ていない | キュー経由でメインスレッドから更新 |
| 稀に落ちる | 別スレッドから部品を直接操作 | 画面更新はメインスレッドに限定 |
配置は3方式を混ぜない
部品の配置には pack / grid / place の3方式があります。同じ親ウィジェットの中で混ぜると配置が壊れるため、どれを使うかを決めてから書き始めます。
| 方式 | 向いている場面 |
|---|---|
pack | 上から順に積むだけの単純な画面 |
grid | 入力欄とラベルが並ぶフォーム状の画面 |
place | 座標を直接指定したいとき(可変サイズに弱い) |
実務で最も使うのは grid です。行と列で位置を指定でき、ウィンドウのリサイズに追従させる設定(columnconfigure の重み付け)も素直に書けます。親が違えば方式を変えても構わないため、フレーム単位で使い分けるのが現実的な運用です。
CLIとGUIの使い分け
同じ処理を [[CLI設計(argparse・click)]] とGUIのどちらで提供するかは、使う人と繰り返しの有無で決めます。
- 手順を自動化したい・他のツールとつなげたい → CLI
- 操作する人がターミナルを使わない → GUI
現実的なのは、処理本体を関数として切り出し、CLIとGUIの両方から呼ぶ構成です。ロジックがどちらにも依存しなければ、後から入口を足せます。配布時は [[PyInstaller配布]] で単一実行ファイルにまとめると、Python未導入の端末へも渡せます。
関連技術とのつながり
- [[Python]] — 標準ライブラリに含まれるため追加依存なしで始められる
- [[PyInstaller配布]] — 作ったGUIをPython未導入の端末へ配るときの定番
- [[CLI設計(argparse・click)]] — 同じ処理本体を別の入口から提供する選択肢
Q: TkinterのGUIで画面が固まる主な原因はどれ?
- [ ] ウィンドウのサイズが大きすぎる
- [x] 時間のかかる処理をイベントループと同じ流れで実行している
- [ ] ボタンの数が多すぎる
解説: `mainloop()` は操作を待ち続ける流れです。そこで重い処理を実行すると描画も操作も止まります。
Q: 別スレッドで重い処理を動かすときの注意点はどれ?
- [x] 別スレッドから画面部品を直接操作しない
- [ ] スレッドは必ず2つまでにする
- [ ] 処理が終わるまでウィンドウを非表示にする
解説: 画面の更新はメインスレッドに限定し、結果はキューなどを経由して受け渡します。
Q: 同じ処理をCLIとGUIの両方で提供したいときの構成はどれ?
- [ ] GUI側にロジックを書き、CLIから画面を起動する
- [x] 処理本体を関数として切り出し、CLIとGUIの両方から呼ぶ
- [ ] 同じコードを2つ複製して個別に保守する
解説: ロジックが入口に依存しなければ、後からどちらの入口も足せます。