Rozdział 16 · Tworzenie fajnych aplikacji z Tkinter
Mini-projekt: lista zadania
Proste lista linii i cała mała aplikacja z zapisywaniem między przejściami.
Lista zadań — integracja rozdziału 11 (listy), rozdziału 15 (JSON) i Tkinter (Listbox).
tasks : list[str]
ekspozycja
↓Listbox
callback
↓add_task() / remove_task()
wytrwałości
↓todo.json
todo_logika.py
import json
from pathlib import Path
def load_tasks(path):
if not path.exists():
return []
with path.open("r", encoding="utf-8") as f:
return json.load(f)
def save_tasks(path, tasks):
with path.open("w", encoding="utf-8") as f:
json.dump(tasks, f, ensure_ascii=False, indent=2)
def add_task(tasks, text):
if not text.strip():
return tasks
return tasks + [text.strip()]
def remove_task(tasks, index):
return tasks[:index] + tasks[index + 1:]
Pojedyncze funkcje callback bez klasy są źródłem błędu
Callback trochę
on_add(), zadeklarowany samodzielnie (nie w innej funkcji), nie można użyć nonlocal tasks — nonlocal wymaga zmiennej z funkcji obejmującej, a nie z zakresu globalnego. Bardziej odpowiednią klasą zastosowań tutaj (Rozdział 14) jest self.tasks rozwiązuje ten problem naturalnie.todo_gui.py
class TodoApp:
def __init__(self, root, path):
self.root = root
self.path = path
self.tasks = load_tasks(path)
self.new_task_var = tk.StringVar()
self.listbox = tk.Listbox(root, height=6)
self.listbox.pack()
entry = ttk.Entry(root, textvariable=self.new_task_var)
entry.pack(side="left", fill="x", expand=True)
ttk.Button(root, text="+", command=self.on_add).pack(side="left")
ttk.Button(root, text="−", command=self.on_delete).pack(side="left")
self.refresh_listbox()
def refresh_listbox(self):
self.listbox.delete(0, "end")
for task in self.tasks:
self.listbox.insert("end", task)
def on_add(self):
self.tasks = add_task(self.tasks, self.new_task_var.get())
self.new_task_var.set("")
self.refresh_listbox()
save_tasks(self.path, self.tasks)
def on_delete(self):
selected = self.listbox.curselection()
if not selected:
return
self.tasks = remove_task(self.tasks, selected[0])
self.refresh_listbox()
save_tasks(self.path, self.tasks)
Logika jest sprawdzalna bez żadnego widżetu
add_task, remove_task, load_tasks, save_tasks są zwykłe funkcje z listami i słownikami. To właśnie sprawdza praktyka tej sekcji — dokładnie ten podział omawiany w sekcji 16.24.Praktyka: Logika listy zadań
Sprawdziłem bez tkinter – funkcje pracy z listą zadań