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

Web APP Python
スポンサーリンク

7日目のゴール

7日目のテーマは
「ここまでの GUI 基礎とボタンイベントを“1つの完成アプリ”としてまとめる」 ことです。

これまで6日間であなたはすでに、

ウィンドウ・ラベル・ボタン・Entry・Listbox
pack / grid / Frame によるレイアウト
ボタンで状態を切り替える
ボタンでデータを追加・更新・表示する

という、GUIアプリの土台を全部通っています。

7日目では、それらを統合して、

画面切り替え
入力フォーム
一覧表示
削除(確認ダイアログ付き)

を備えた「小さなタスク管理 GUI アプリ」を完成させます。


アプリの全体像を言葉で設計する

どんな GUI アプリを作るか

作るのは、シンプルな「タスク管理アプリ」です。

タスク名を入力して追加できる
登録されたタスクを一覧で見られる
一覧からタスクを選んで削除できる
削除時には確認ダイアログを出す
画面は「入力」と「一覧」を切り替えられる

ここに、7日間で学んだ要素を全部乗せていきます。


データ構造と「真実の置き場所」

タスクはどこに保存しておくか

まずは、アプリの中でタスクをどう持つかを決めます。

ここではシンプルに、
「文字列のリスト」として持ちます。

tasks = []
Python

この tasks が「真実のデータ」です。
Listbox はあくまで「画面に見せるためのコピー」です。

この「本体(tasks)と表示(Listbox)を分ける」意識が、
中級者としてとても大事なポイントです。


画面構成:メニュー・入力・一覧

Frame で画面を分ける

ウィンドウの中を、ざっくり3つのエリアに分けます。

上部:画面切り替えボタン(メニュー)
中央:入力画面(Frame)
中央:一覧画面(別の Frame)

メニューは常に表示し、
中央部分だけ「入力」か「一覧」かを切り替えます。

import tkinter as tk
from tkinter import messagebox

tasks = []

def show_input_frame():
    frame_list.pack_forget()
    frame_input.pack(fill="both", expand=True)

def show_list_frame():
    frame_input.pack_forget()
    refresh_listbox()
    frame_list.pack(fill="both", expand=True)

root = tk.Tk()
root.title("タスク管理アプリ")

frame_menu = tk.Frame(root)
frame_menu.pack(fill="x")

button_to_input = tk.Button(frame_menu, text="タスク入力", command=show_input_frame)
button_to_input.pack(side="left", padx=5, pady=5)

button_to_list = tk.Button(frame_menu, text="タスク一覧", command=show_list_frame)
button_to_list.pack(side="left", padx=5, pady=5)

frame_input = tk.Frame(root)
frame_list = tk.Frame(root)
Python

ここでの重要ポイントは、

入力用 Frame と一覧用 Frame を両方作っておき、
「どちらを pack するか」で画面を切り替えていることです。


入力画面:タスク追加の流れを作る

Entry とボタンでタスクを追加する

入力画面には、

タスク名のラベル
タスク名の Entry
「追加」ボタン
メッセージ表示用ラベル

を置きます。

label_task = tk.Label(frame_input, text="タスク名:")
label_task.grid(row=0, column=0, padx=5, pady=5, sticky="e")

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=lambda: add_task())
button_add.grid(row=0, column=2, padx=5, pady=5)

label_message = tk.Label(frame_input, text="タスク名を入力して「追加」を押してください。")
label_message.grid(row=1, column=0, columnspan=3, pady=10)
Python

ここでは grid を使って、
ラベル・Entry・ボタンを横一列に並べています。


タスク追加のロジック

add_task 関数を丁寧に分解する

def add_task():
    text = entry_task.get().strip()
    if text == "":
        label_message.config(text="タスク名が空です。入力してください。")
        return

    tasks.append(text)
    entry_task.delete(0, tk.END)
    label_message.config(text=f"タスク「{text}」を追加しました。")
Python

この関数の役割は、
「追加ボタンが押されたときの一連の流れ」です。

Entry から文字列を取り出す
空ならエラーメッセージを表示して終了
空でなければ tasks に追加する
入力欄を空に戻す
メッセージラベルでフィードバックする

ここでの重要ポイントは、

データを変えているのは tasks.append(text) の1行だけ
それ以外は全部「画面の状態を変える処理」

ということです。

この意識があると、
後で「保存」「読み込み」を足すときに、
どこを触ればいいかがすぐ分かります。


一覧画面:Listbox と削除ボタン

Listbox にタスク一覧を表示する

一覧画面には、

「タスク一覧」というラベル
タスクを表示する Listbox
「削除」ボタン
ステータスメッセージ用ラベル

を置きます。

label_list_title = tk.Label(frame_list, text="タスク一覧")
label_list_title.pack(pady=5)

listbox_tasks = tk.Listbox(frame_list, height=8, width=40)
listbox_tasks.pack(padx=10, pady=5)

button_delete = tk.Button(frame_list, text="選択したタスクを削除", command=lambda: delete_task())
button_delete.pack(pady=5)

label_status = tk.Label(frame_list, text="タスクを選択して「削除」を押してください。")
label_status.pack(pady=5)
Python

Listbox は、
「tasks の中身をユーザーに見せる窓」
という位置づけです。


一覧の更新:refresh_listbox

データと表示を同期させる

def refresh_listbox():
    listbox_tasks.delete(0, tk.END)
    for task in tasks:
        listbox_tasks.insert(tk.END, task)
Python

この関数は、
「今の tasks の内容を Listbox に反映する」
という一点だけを担当します。

show_list_frame の中でこれを呼ぶことで、

一覧画面に切り替えたタイミングで
常に最新のタスク一覧が表示される

という状態を作っています。


削除処理:選択・確認・削除・再表示

delete_task の流れを丁寧に追う

def delete_task():
    selection = listbox_tasks.curselection()
    if not selection:
        label_status.config(text="削除するタスクを選択してください。")
        return

    index = selection[0]
    task = tasks[index]

    result = messagebox.askokcancel("確認", f"「{task}」を削除しますか?")
    if not result:
        label_status.config(text="削除をキャンセルしました。")
        return

    del tasks[index]
    refresh_listbox()
    label_status.config(text=f"タスク「{task}」を削除しました。")
Python

ここには、7日目のエッセンスが詰まっています。

listbox_tasks.curselection() で、
「今選ばれている行のインデックス」を取得しています。
何も選ばれていなければ、メッセージを出して終了。

選ばれていれば、そのインデックスから
tasks[index] で本体のタスクを取り出します。

削除前に messagebox.askokcancel で確認ダイアログを出し、
OK が押されたときだけ削除を実行します。

削除は del tasks[index] で本体から消し、
refresh_listbox() で表示を更新し、
最後にステータスメッセージを更新します。

ここでの超重要ポイントは、

削除の対象はあくまで tasks(本体)
Listbox は refresh_listbox で「後から追従する」

という構造になっていることです。


全コード(完成版)

7日目の統合 GUI アプリ

import tkinter as tk
from tkinter import messagebox

tasks = []

def add_task():
    text = entry_task.get().strip()
    if text == "":
        label_message.config(text="タスク名が空です。入力してください。")
        return

    tasks.append(text)
    entry_task.delete(0, tk.END)
    label_message.config(text=f"タスク「{text}」を追加しました。")

def refresh_listbox():
    listbox_tasks.delete(0, tk.END)
    for task in tasks:
        listbox_tasks.insert(tk.END, task)

def delete_task():
    selection = listbox_tasks.curselection()
    if not selection:
        label_status.config(text="削除するタスクを選択してください。")
        return

    index = selection[0]
    task = tasks[index]

    result = messagebox.askokcancel("確認", f"「{task}」を削除しますか?")
    if not result:
        label_status.config(text="削除をキャンセルしました。")
        return

    del tasks[index]
    refresh_listbox()
    label_status.config(text=f"タスク「{task}」を削除しました。")

def show_input_frame():
    frame_list.pack_forget()
    frame_input.pack(fill="both", expand=True)

def show_list_frame():
    frame_input.pack_forget()
    refresh_listbox()
    frame_list.pack(fill="both", expand=True)

root = tk.Tk()
root.title("タスク管理アプリ")

frame_menu = tk.Frame(root)
frame_menu.pack(fill="x")

button_to_input = tk.Button(frame_menu, text="タスク入力", command=show_input_frame)
button_to_input.pack(side="left", padx=5, pady=5)

button_to_list = tk.Button(frame_menu, text="タスク一覧", command=show_list_frame)
button_to_list.pack(side="left", padx=5, pady=5)

frame_input = tk.Frame(root)

label_task = tk.Label(frame_input, text="タスク名:")
label_task.grid(row=0, column=0, padx=5, pady=5, sticky="e")

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=add_task)
button_add.grid(row=0, column=2, padx=5, pady=5)

label_message = tk.Label(frame_input, text="タスク名を入力して「追加」を押してください。")
label_message.grid(row=1, column=0, columnspan=3, pady=10)

frame_list = tk.Frame(root)

label_list_title = tk.Label(frame_list, text="タスク一覧")
label_list_title.pack(pady=5)

listbox_tasks = tk.Listbox(frame_list, height=8, width=40)
listbox_tasks.pack(padx=10, pady=5)

button_delete = tk.Button(frame_list, text="選択したタスクを削除", command=delete_task)
button_delete.pack(pady=5)

label_status = tk.Label(frame_list, text="タスクを選択して「削除」を押してください。")
label_status.pack(pady=5)

frame_input.pack(fill="both", expand=True)

root.mainloop()
Python

この1ファイルの中に、
7日間で学んだ GUI 基礎とボタンイベントのエッセンスが
ほぼ全部入っています。


7日目で絶対に押さえてほしい本質

「画面」「データ」「ボタン」が一本の線でつながった状態

ここまで来たあなたはもう、

画面(Frame / Label / Entry / Listbox)を設計できる
データ(リストや変数)をどこに持つか決められる
ボタンで「いつ」「何を」「どう変えるか」を考えられる

というところまで来ています。

今日のタスク管理アプリで、
特に意識してほしいのはこの3つです。

データの本体は tasks にある(画面はあくまで表示)
画面切り替えは Frame の表示・非表示で行う
ボタンは「データの変更」と「画面の更新」の両方を担当する

この感覚が身につけば、
あとは「何を作りたいか」を決めるだけで、
tkinter でかなりいろいろなアプリが作れるようになります。

ここから先は、あなたの番です。

タスクに期限を付けてみる
優先度を付けて並び替えてみる
JSON 保存アプリで学んだ保存機能を組み合わせてみる

どれも、もう十分に手が届く範囲です。
「自分の生活で本当に使いたい小さなツール」を、
一つだけでいいので、tkinter で形にしてみてください。
そこから先が、本当の“自分のプログラミング”になっていきます。

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