Python | 1 日 120 分 × 7 日アプリ学習:tkinterで作るGUIアプリ(中級編)

Web APP Python
スポンサーリンク
スポンサーリンク

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アプリ」に仕上げていきましょう。

タイトルとURLをコピーしました