5日目のゴール
5日目のテーマは
「ボタンを“アプリの司令塔”として使いこなす」 ことです。
ここまでであなたはすでに、
ボタンを押して関数を呼べる
複数ボタンを使い分けられる
Entry と組み合わせて入力を処理できる
grid や Frame で画面をそれっぽく整えられる
というところまで来ています。
5日目では一歩進んで、
ボタンで「状態」を切り替える
ボタンの有効・無効を制御する
確認ダイアログ(OK/キャンセル)を挟む
イベントバインドで「クリックそのもの」を扱う
といった、「ボタンを中心にアプリの流れをデザインする」感覚を育てます。
ボタンは「ただ押すもの」ではなく「状態を変えるスイッチ」
状態を持ったボタンのイメージ
これまでのボタンは、
押す → 何か処理が走る → 終わり
という「一発屋」的な使い方が多かったはずです。
でも、実際のアプリでは、
押すたびに ON/OFF が切り替わる
押したら他のボタンが押せなくなる
押す前と押した後で、画面の意味が変わる
という、「状態を変えるスイッチ」としてのボタンがよく出てきます。
まずは、シンプルな「編集モード切り替えボタン」を作ってみましょう。
import tkinter as tk
is_edit_mode = False
def toggle_edit_mode():
global is_edit_mode
if is_edit_mode:
label_mode.config(text="閲覧モード")
button_toggle.config(text="編集モードにする")
entry_name.config(state="disabled")
is_edit_mode = False
else:
label_mode.config(text="編集モード")
button_toggle.config(text="閲覧モードにする")
entry_name.config(state="normal")
is_edit_mode = True
root = tk.Tk()
root.title("編集モード切り替え")
label_mode = tk.Label(root, text="閲覧モード")
label_mode.pack(pady=5)
entry_name = tk.Entry(root)
entry_name.insert(0, "ここに名前が入ります")
entry_name.config(state="disabled")
entry_name.pack(pady=5)
button_toggle = tk.Button(root, text="編集モードにする", command=toggle_edit_mode)
button_toggle.pack(pady=5)
root.mainloop()
Pythonここでの重要ポイントは三つです。
一つ目は、is_edit_mode というフラグで「今どの状態か」を覚えていること。
二つ目は、ボタンの text もラベルの text も、状態に応じて変えていること。
三つ目は、Entry の state を "normal" と "disabled" で切り替えていることです。
このパターンを覚えると、「モード切り替え」「ロック」「一時停止」など、いろんな場面に応用できます。
ボタンの有効・無効を「アプリの流れ」で制御する
まだ押してほしくないボタンを無効にしておく
例えば、こんな流れを考えます。
名前を入力する
「確認」ボタンを押す
確認が終わるまでは「送信」ボタンは押せない
このとき、「送信」ボタンを最初から無効にしておき、
「確認」が終わったら有効にする、という設計が自然です。
import tkinter as tk
def on_check():
name = entry_name.get().strip()
if name == "":
label_status.config(text="名前を入力してください。")
button_submit.config(state="disabled")
else:
label_status.config(text=f"名前: {name} でよろしいですか?")
button_submit.config(state="normal")
def on_submit():
label_status.config(text="送信しました。(ダミー)")
button_submit.config(state="disabled")
root = tk.Tk()
root.title("確認付き送信")
label_name = tk.Label(root, text="名前:")
label_name.grid(row=0, column=0, padx=5, pady=5, sticky="e")
entry_name = tk.Entry(root)
entry_name.grid(row=0, column=1, padx=5, pady=5)
button_check = tk.Button(root, text="確認", command=on_check)
button_check.grid(row=1, column=0, padx=5, pady=5)
button_submit = tk.Button(root, text="送信", command=on_submit, state="disabled")
button_submit.grid(row=1, column=1, padx=5, pady=5)
label_status = tk.Label(root, text="名前を入力して「確認」を押してください。")
label_status.grid(row=2, column=0, columnspan=2, pady=10)
root.mainloop()
Pythonここでの本質は、
ボタンの state を
「アプリの状態に応じて変える」ことで、
ユーザーの操作の順番を自然に誘導している
ということです。
「押してほしくないときは押せないようにする」
これは、エラーを減らすためのとても強い設計です。
確認ダイアログを挟む(messagebox)
「本当にいいですか?」を GUI で聞く
何かを削除するときや、アプリを終了するときなど、
「本当に実行していいか」を確認したくなる場面があります。
tkinter には、そのためのダイアログを出す messagebox があります。
import tkinter as tk
from tkinter import messagebox
def on_delete_click():
result = messagebox.askokcancel("確認", "本当に削除しますか?")
if result:
label_status.config(text="削除しました。(ダミー)")
else:
label_status.config(text="削除をキャンセルしました。")
root = tk.Tk()
root.title("確認ダイアログ")
button_delete = tk.Button(root, text="削除", command=on_delete_click)
button_delete.pack(pady=10)
label_status = tk.Label(root, text="削除ボタンを押してみてください。")
label_status.pack(pady=10)
root.mainloop()
Pythonここでの重要ポイントを深掘りします。
from tkinter import messagebox でダイアログ機能を読み込む。messagebox.askokcancel(title, message) は、「OK」と「キャンセル」のボタンが付いたダイアログを出し、ユーザーが OK を押したら True、キャンセルなら False を返す。
ボタンイベントの中で、その戻り値を見て処理を分岐している。
これで、
ボタンを押す
確認ダイアログが出る
ユーザーの選択に応じて処理が変わる
という、「一段階深いボタンイベント」が作れます。
ボタン以外のイベントも扱ってみる(クリックイベントのバインド)
command ではなく「クリックそのもの」に反応する
ここまでのボタンイベントは、command= に関数を渡すスタイルでした。
tkinter にはもう一つ、
「イベントを文字列で指定してバインドする」方法があります。
例えば、左クリックは <Button-1> というイベント名です。
import tkinter as tk
def on_button_left_click(event):
label_status.config(text="左クリックされました。")
root = tk.Tk()
root.title("イベントバインド")
button = tk.Button(root, text="クリックしてみて")
button.pack(pady=10)
label_status = tk.Label(root, text="ここに状態が表示されます。")
label_status.pack(pady=10)
button.bind("<Button-1>", on_button_left_click)
root.mainloop()
Pythonここでのポイントは二つです。
一つ目は、bind("<Button-1>", 関数) という形で、「このイベントが起きたらこの関数を呼んで」と登録していること。
二つ目は、on_button_left_click の引数に event があることです。
command= のときは引数なしの関数でしたが、bind で登録する関数は、
「イベントの情報が入った event オブジェクト」を受け取ります。
2D目・3日目の段階では、
「bind を使うと、クリックの種類や位置など、より細かいイベントが扱える」
くらいの理解で十分です。
ボタンで「アプリを終了する」
終了ボタンも立派なボタンイベント
アプリにはたいてい「終了」ボタンがあります。
tkinter では、root.destroy() を呼ぶとウィンドウを閉じてアプリを終了できます。
import tkinter as tk
from tkinter import messagebox
def on_exit_click():
result = messagebox.askyesno("終了確認", "アプリを終了してもよろしいですか?")
if result:
root.destroy()
root = tk.Tk()
root.title("終了ボタン付きアプリ")
button_exit = tk.Button(root, text="終了", command=on_exit_click)
button_exit.pack(pady=20)
root.mainloop()
Pythonここでは、
終了ボタンを押す
確認ダイアログ(はい/いいえ)が出る
「はい」なら root.destroy() で終了
という流れになっています。
「終了もボタンイベントの一つ」
と捉えると、アプリ全体の流れをボタンでコントロールしやすくなります。
5日目のミニアプリ:簡易タスク完了管理
仕様
タスク名を入力して「追加」ボタンで登録
登録されたタスクはラベルで表示(簡易版)
「完了」ボタンを押すと、確認ダイアログを出してから「完了しました」と表示
完了後は「完了」ボタンを無効にする
コード
import tkinter as tk
from tkinter import messagebox
current_task = None
def on_add_click():
global current_task
text = entry_task.get().strip()
if text == "":
label_status.config(text="タスク名を入力してください。")
return
current_task = text
label_task.config(text=f"現在のタスク: {current_task}")
label_status.config(text="タスクが追加されました。")
button_done.config(state="normal")
entry_task.delete(0, tk.END)
def on_done_click():
global current_task
if current_task is None:
return
result = messagebox.askokcancel("確認", f"「{current_task}」を完了にしますか?")
if result:
label_status.config(text=f"タスク「{current_task}」は完了しました。")
label_task.config(text="現在のタスク: なし")
current_task = None
button_done.config(state="disabled")
root = tk.Tk()
root.title("簡易タスク完了管理")
frame_input = tk.Frame(root)
frame_input.pack(padx=10, pady=10)
frame_task = tk.Frame(root)
frame_task.pack(padx=10, pady=10)
frame_status = tk.Frame(root)
frame_status.pack(padx=10, pady=10)
label_entry = tk.Label(frame_input, text="タスク名:")
label_entry.grid(row=0, column=0, padx=5, pady=5)
entry_task = tk.Entry(frame_input, width=30)
entry_task.grid(row=0, column=1, padx=5, pady=5)
button_add = tk.Button(frame_input, text="追加", command=on_add_click)
button_add.grid(row=0, column=2, padx=5, pady=5)
label_task = tk.Label(frame_task, text="現在のタスク: なし")
label_task.pack()
button_done = tk.Button(frame_task, text="完了", command=on_done_click, state="disabled")
button_done.pack(pady=5)
label_status = tk.Label(frame_status, text="タスクを追加してください。")
label_status.pack()
root.mainloop()
Pythonここには、5日目のエッセンスが詰まっています。
タスクの「状態」を current_task で管理している。
「完了」ボタンは、タスクがあるときだけ有効にしている。
完了時には確認ダイアログを挟んでいる。
完了後はボタンを無効にして、状態をリセットしている。
ボタンが、
「ただ押されるもの」ではなく
「アプリの状態を進めるトリガー」になっているのが分かると思います。
5日目で絶対に押さえてほしい本質
ボタンは「アプリの流れ」と「状態」をつなぐ存在
今日いちばん大事なのは、
ボタンは
「関数を呼ぶスイッチ」
であると同時に、
アプリの状態を変える
他の部品の状態(有効・無効)を変える
ユーザーの操作の順番をデザインする
ための「司令塔」だ、という感覚です。
キーワードをまとめると、
ボタンの state を "normal" と "disabled" で切り替えるmessagebox で確認ダイアログを挟むroot.destroy() で終了ボタンを作る
必要に応じて bind で細かいイベントも扱える
ここまで来ると、
ボタンイベントはもう「ただのクリック処理」ではなく、
アプリ全体の流れをコントロールするための道具になっています。
6日目・7日目では、
これまでの GUI 基礎とボタンイベントを、
ファイル保存やエラーハンドリングと組み合わせて、
「本当に使える小さなGUIアプリ」に仕上げていきましょう。

