Rozdział 16 · Tworzenie fajnych aplikacji z Tkinter
Mini-Projekt: Edytor Notatek
Dziennik notatek z rozdziału 15 wreszcie dostaje prawdziwe okno i menu.
Bezpośrednia kontynuacja dziennika notatek z rozdziału 15 (15.4) – teraz z prawdziwym oknem, pole wieloliniowe oraz menu „Plik”
redaktor_zametok.py
class NotesEditorApp:
def __init__(self, root):
self.root = root
self.current_path = None
self.dirty = False
self.text_widget = ScrolledText(root, wrap="word")
self.text_widget.pack(fill="both", expand=True)
self.text_widget.bind("<<Modified>>", self.on_text_modified)
self.build_menu()
self.root.protocol("WM_DELETE_WINDOW", self.on_exit)
def on_text_modified(self, event):
self.dirty = True
self.text_widget.edit_modified(False) # zresetuj wbudowaną flagę Tk
def confirm_discard_if_dirty(self):
"""True — można kontynuować (New/Open/Exit). False — użytkownik zmienił zdanie."
if not self.dirty:
return True
answer = messagebox.askyesnocancel(
„Niezapisane zmiany”,
„Zapisz zmiany przed kontynuowaniem?”,
)
if answer is None: #Cancel – Przerwij bieżącą aktywność
return False
if answer: #Yes – Kontynuuj tylko wtedy, gdy zapis faktycznie się powiódł
return self.save_as()
return True # No — kontynuuj, nie zapisując
def on_exit(self):
if self.confirm_discard_if_dirty():
self.root.destroy()
def save_as(self):
"""True - Plik został zapisany. False - Użytkownik anulował okno "Zapisz jako".
filename = filedialog.asksaveasfilename(defaultextension=".txt")
if not filename:
return False
self.current_path = Path(filename)
self.current_path.write_text(self.text_widget.get("1.0", "end-1c"), encoding="utf-8")
self.dirty = False
return True
Trzy wyniki jednego pytania
messagebox.askyesnocancel(...) zwroty True (Tak – zapisz), False (Brak – Nie zapisuj) lub None (Anuluj/zamknij dialog — całkowicie przerwij bieżącą akcję). Normalne askyesno można zrobić tylko dwie pierwsze opcje — do „Wyjścia z niezapisanymi zmianami”Yes – jeszcze nie został uratowany
Jeśli użytkownik wybrał „Tak”, ale następnie kliknął „Anuluj” w dialogu
asksaveasfilename, plik nie został zapisany — i kontynuowanie działania (zamykanie okna, otwieranie innego pliku) jest niemożliwe, w przeciwnym razie niezapisany tekst zostanie utracony. Dlatego confirm_discard_if_dirty() zwraca wynik save_as(), nie True natychmiast po zadzwonieniu „Tak”Nic fundamentalnie nowego w plikach
filedialog (16.19), Path.read_text/write_text(encoding="utf-8") (Rozdział 15), ScrolledText (gotowa kombinacja Text + Scrollbar) — wszystkie części są już znane, tutaj są zebrane w jednym zastosowaniu.★★ Zadanie samodzielne
Nowy i Otwórz też pytają
Dodaj new_file() i open_file() metod, z których każda wywołuje confirm_discard_if_dirty() jako pierwsza — i kontynuuje tylko wtedy, gdy zwróciła True.
Praktyka: Edytor notatek
Moduł tkinter otwiera natywne okno Python — wykonaj lokalnie w VS Code, PyCharm lub Jupyter
Praktyka kursuje lokalnie