はじめに
Tkinterを使用してマルチウィンドウアプリケーションを開発する際、課題の一つが「ウィンドウ間でのデータ共有」です。この記事では、コールバック関数を使用したデータ共有の実装方法について、具体的な実装例とともに解説します。
実装するアプリケーションの概要
シンプルなタスク管理アプリケーションを例に、ウィンドウ間でのデータ共有を実装します。
- メインウィンドウ:タスク一覧を表示
- サブウィンドウ:新規タスクの入力
- データ共有:入力されたタスクをメインウィンドウのリストに反映
コード実装
import tkinter as tk
from tkinter import ttk
from tkinter import messagebox
from datetime import datetime
class MainWindow:
def __init__(self):
self.root = tk.Tk()
self.root.title("タスク管理")
self.root.geometry("400x500")
# タスク一覧を表示するTreeview
self.tree = ttk.Treeview(self.root, columns=('Task', 'Priority', 'Due Date'))
self.tree.heading('Task', text='タスク')
self.tree.heading('Priority', text='優先度')
self.tree.heading('Due Date', text='期限')
self.tree.column('#0', width=0, stretch=tk.NO) # 非表示の先頭カラムを幅0に
self.tree.pack(pady=10, padx=10, fill=tk.BOTH, expand=True)
# 新規タスク追加ボタン
self.add_button = tk.Button(
self.root,
text="新規タスク追加",
command=self.open_task_window
)
self.add_button.pack(pady=10)
# タスクの合計を表示するラベル
self.total_label = tk.Label(self.root, text="合計タスク数: 0")
self.total_label.pack(pady=5)
def open_task_window(self):
"""タスク入力ウィンドウを開く"""
TaskWindow(self.root, self.add_task)
def add_task(self, task_data):
"""
新規タスクを追加するコールバック関数
TaskWindowから呼び出される
"""
# Treeviewにタスクを追加
self.tree.insert(
'',
'end',
values=(
task_data['task'],
task_data['priority'],
task_data['due_date']
)
)
# 合計タスク数を更新
total = len(self.tree.get_children())
self.total_label.config(text=f"合計タスク数: {total}")
def run(self):
"""アプリケーションの実行"""
self.root.mainloop()
class TaskWindow:
def __init__(self, master, callback):
# コールバック関数を保持
self.callback = callback
# ウィンドウの作成
self.window = tk.Toplevel(master)
self.window.title("新規タスク")
self.window.geometry("300x400")
# タスク名入力
tk.Label(self.window, text="タスク名:").pack(pady=(10, 0))
self.task_entry = tk.Entry(self.window, width=40)
self.task_entry.pack(pady=(0, 10))
# 優先度選択
tk.Label(self.window, text="優先度:").pack(pady=(10, 0))
self.priority_var = tk.StringVar(value="中")
priorities = ["高", "中", "低"]
self.priority_combo = ttk.Combobox(
self.window,
textvariable=self.priority_var,
values=priorities,
state="readonly"
)
self.priority_combo.pack(pady=(0, 10))
# 期限日入力
tk.Label(self.window, text="期限日 (YYYY-MM-DD):").pack(pady=(10, 0))
self.due_date_entry = tk.Entry(self.window, width=40)
self.due_date_entry.pack(pady=(0, 10))
# 保存ボタン
self.save_button = tk.Button(
self.window,
text="保存",
command=self.save_task
)
self.save_button.pack(pady=20)
# ウィンドウを親の中央に配置
self.window.transient(master)
self.window.grab_set()
def save_task(self):
"""タスクを保存し、コールバック関数を呼び出す"""
# 入力値の取得と検証
task = self.task_entry.get().strip()
priority = self.priority_var.get()
due_date = self.due_date_entry.get().strip()
# 入力チェック
if not task:
messagebox.showwarning("警告", "タスク名を入力してください")
return
if not due_date:
messagebox.showwarning("警告", "期限日を入力してください")
return
# 日付形式のチェック
try:
datetime.strptime(due_date, '%Y-%m-%d')
except ValueError:
messagebox.showwarning(
"警告",
"期限日はYYYY-MM-DD形式で入力してください\n例: 2024-12-31"
)
return
# データを辞書形式でまとめる
task_data = {
'task': task,
'priority': priority,
'due_date': due_date
}
# コールバック関数を呼び出してデータを渡す
self.callback(task_data)
# ウィンドウを閉じる
self.window.destroy()
if __name__ == "__main__":
app = MainWindow()
app.run()
コードの解説
1. データ共有の仕組み
この実装では、以下の流れでウィンドウ間のデータ共有を実現しています:
- メインウィンドウ(
MainWindow
)がコールバック関数(add_task
)を用意 - サブウィンドウ(
TaskWindow
)の作成時にコールバック関数を渡す - サブウィンドウでデータが入力され保存ボタンが押されると、コールバック関数を通じてデータをメインウィンドウに渡す
2. 重要なポイント
コールバック関数の受け渡し
def open_task_window(self):
TaskWindow(self.root, self.add_task) # コールバック関数を渡す
コールバック関数の保持
def __init__(self, master, callback):
self.callback = callback # コールバック関数を保持
データの受け渡し
# サブウィンドウでデータを辞書形式にまとめる
task_data = {
'task': task,
'priority': priority,
'due_date': due_date
}
# コールバック関数を呼び出してデータを渡す
self.callback(task_data)
3. エラーハンドリング
入力値の検証とエラーメッセージの表示を実装しています:
- 必須項目のチェック
- 日付形式の検証
- ユーザーへのフィードバック
4. リソース管理
サブウィンドウの適切な管理のため、以下の実装を行っています:
-
transient(master)
による親ウィンドウとの関連付け -
grab_set()
によるモーダルウィンドウ化 - 処理完了時の
destroy()
によるリソース解放
実行結果
このコードを実行すると:
- タスク一覧を表示するメインウィンドウが表示されます
- 「新規タスク追加」ボタンをクリックすると、タスク入力用のサブウィンドウが開きます
- サブウィンドウでタスクを入力し保存すると、メインウィンドウのリストに追加されます
- タスクが追加されるたびに、合計タスク数が更新されます
まとめ
コールバック関数を使用したウィンドウ間のデータ共有には、以下のメリットがあります:
- シンプルな実装: 複雑な状態管理が不要
- 疎結合: ウィンドウ間の依存関係が最小限
- 柔軟性: データの受け渡し方法を自由に定義可能