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をコピーしました