Rozdział 16 · Tworzenie fajnych aplikacji z Tkinter
after(): timery bez blokowania
Czekanie nie oznacza zatrzymania całej aplikacji.
after() - Odroczone połączenie bez blokowania
after_prosto.py
after_id = root.after(1000, lambda: print(„Minęła sekunda”))
# program nadal przetwarza inne wydarzenia, czekając na tę sekundę
Pętla Zdarzeń
↓
planować after()
↓
inne zdarzenia są nadal przetwarzane
callback nazywa się
↓nadszedł czas
„Za sekundę” — nie jest to stoper z dokładnością do milisekundy
after(1000, callback) oznacza „przygotuj callback do wykonania mniej więcej za 1000 ms, kiedy cykl zdarzeń będzie mógł go obsłużyć” — nie gwarantuje wykonania dokładnie w podanej milisekundzie. Jeśli w tym momencie cykl jest zajęty innym zdarzeniem, wywołanie nastąpi trochę później.Powtarzający się timer (self-rescheduling)
tik.py
after_id = None
def tik():
global after_id
label.config(text=f"Sekundy: {schet.get()}")
schet.set(schet.get() + 1)
after_id = root.after(1000, tik) # planuje się na nowo – to jest powtarzalność
Nie tylko for/while jest powtarzalną
Z rozdziału 10 znamy cykle
for/while. Powtarzające się połączenia przez self-scheduling after() inny sposób organizacji powtarzania na podstawie zdarzeń, a nie sekwencyjnego bloku kodu.Każdy nowy after() musi zaktualizować zapisane id
U
tik() nowe wyzwanie after() przy każdym zaznaczeniu, a więc nowy identyfikator. Jeśli nie przydzielisz ponownie after_id na każdym połączeniu (jak wyżej) zapisany zmienna szybko staje się przestarzały — będzie wskazywał już wywołane połączenie, a nie faktycznie oczekujące, a próba zatrzymania timera na tym id niczego nie zatrzyma.Zatrzymanie timera: after_cancel
after_cancel.py
def stop():
global after_id
if after_id is not None:
root.after_cancel(after_id)
after_id = None
Nie zgub dowodu tożsamości
Aby zatrzymać zaplanowaną rozmowę, musisz zapisać istotne identyfikator, który oddzwonił na ostatnie połączenie
after(). Bez niego nie będziesz mógł anulować tego konkretnego zaplanowanego połączenia. Kompletny model trzech stanów (zatrzymany/w trakcie/zakończony) z ważnym after_id zobacz mini-projekt „Timer”Debug Lab 3: Ponowne uruchomienie tworzy zdublowane timery
duplicate_after.py
def start():
tik() # każde kliknięcie na „Start”
ttk.Button(root, text=„Start”, command=start).pack()
# После нескольких нажатий «Старт» счётчик начинает прыгать сразу на 2, 3, 4 за секунду —
# работает уже несколько параллельных цепочек after().
Każde kliknięcie uruchamia nowy niezależny łańcuch samoplanowanych wywołań tik(), i one się nawzajem nie zastępują, lecz działają jednocześnie. Należy zablokować ponowne uruchomienie przez wspólny znacznik running — i ta sama flaga musi być sprawdzona samodzielnie tik(), w przeciwnym razie łańcuch nie zatrzyma się nawet po stop().
Poprawiony kod
duplicate_after_fixed.py
running = False
after_id = None
def tik():
global after_id, running
if not running:
return # stop() już opuścił flagę – nie planujemy nowej sieci
label.config(text=f"Sekundy: {schet.get()}")
schet.set(schet.get() + 1)
after_id = root.after(1000, tik)
def start():
global running
if running:
return # już działa, zignoruj drugie kliknięcie
running = True
tik()
def stop():
global running, after_id
running = False
if after_id is not None:
root.after_cancel(after_id)
after_id = None
Nigdy nie time.sleep() w callback
time.sleep(...) w obsłudze zatrzymuje całą pętlę zdarzeń na cały czas trwania snu, a interfejs przestaje odpowiadać. Szczegółowy podział można znaleźć w sekcji 16.32.Praktyka: after() odliczanie
Moduł tkinter otwiera natywne okno Python — wykonaj lokalnie w VS Code, PyCharm lub Jupyter
Praktyka kursuje lokalnie