Rozdział 16 · Tworzenie fajnych aplikacji z Tkinter
Architektura aplikacji: logika osobno od widżetów
Najlepszy GUI-logic to ten, który można przetestować nawet bez otwierania okna.
Czysta logika oddzielna od widżetów
Bezpośrednie powiązanie z rozdziałem 13: funkcję domenową można napisać i przetestować niezależnie z interfejsu to po prostu wejście i wyjście, bez żadnego widżetu:
chistaya_logika.py
def calculate_tip(amount, percent, people):
total_tip = amount * percent / 100
return total_tip / people
print(calculate_tip(1000, 15, 2)) # 75.0
callback (obsługa przycisku)
↓
odczytać wartości widgetów
↓
sprawdzić (Rozdział 16.23)
czysta funkcja — bez żadnego widżetu wewnątrz
↓calculate_tip(...)
↓
wyświetlić wynik w widżecie
Callback nie powinien się rozrastać
Jeśli obsługa przycisków zajmuje sto wierszy zagnieżdżonych obliczeń, warto przenieść część tej logiki do osobnej funkcji, którą można zrozumieć i sprawdzić bez uruchamiania okna.
Trochę głębiej: Pułapka późnego wiązania w lambda
Debug Lab 4: Wszystkie przyciski w pętli „pamiętają”
pozdnee_svyazyvanie.py
for i in range(3):
ttk.Button(root, text=str(i), command=lambda: print(i)).pack()
# Все три кнопки выведут одно и то же число — последнее значение i (2),
# а не 0, 1, 2 соответственно.
lambda: print(i) odwołuje się do zmiennej i z okolicznego pola widzenia w momencie kliknięciazamiast momentu utworzenia przycisku (Rozdział 13, Zamknięcia). W momencie kliknięcia cykl już się zakończył, i i jest równe jej ostatniej wartości 2 dla wszystkich trzech przycisków jednocześnie.
Poprawiony kod
pozdnee_svyazyvanie_fixed.py
for i in range(3):
ttk.Button(root, text=str(i), command=lambda i=i: print(i)).pack()
# i=i tworzy wartość domyślną, ustaloną WŁAŚNIE w momencie stworzenia lambda
proverka_lambda_fix.py
callbacks = []
for i in range(3):
callbacks.append(lambda i=i: i)
values = [cb() for cb in callbacks]
print(values) # [0, 1, 2]
Praktyka: Czysta logika i pułapka lambda
Sprawdzane bez tkinter — na funkcjach i domknięciach