Отладка интерфейса и качество GUI
Отзывчивость интерфейса — не автоматическое следствие использования Tkinter, а результат конкретных решений в коде.
Событийный цикл нельзя занимать надолго
import time
def on_click():
time.sleep(5) # "подождать 5 секунд"
label.config(text="Готово!")
# На все 5 секунд окно перестаёт перерисовываться и реагировать на клики —
# событийный цикл заблокирован внутри time.sleep(), а не только сам callback.
time.sleep(...) останавливает весь поток, в котором работает событийный цикл — а Tkinter обычно работает в одном потоке. Пока поток спит, цикл не может обработать вообще ничего: ни перерисовку, ни клики, ни закрытие окна.
def on_click():
label.config(text="Ждём...")
root.after(5000, lambda: label.config(text="Готово!"))
# событийный цикл продолжает работать все эти 5 секунд
while True:
if button_nazhata():
obrabotat_klik()
# Такого кода не должно быть в Tkinter-приложении вообще —
# у Tk уже есть собственный событийный цикл внутри mainloop().
Tkinter уже предоставляет полноценный событийный цикл. Собственный while True для «опроса» состояния виджетов — не нужная и не работающая архитектура: она либо блокирует mainloop(), либо просто избыточна.
button.config(command=obrabotat_klik)
root.mainloop() # cам обрабатывает события, включая клики по button
def on_click():
result = obrabotat_million_zapisej() # секунды вычислений внутри callback
label.config(text=str(result))
# Интерфейс "подвисает" на всё время вычисления — ровно так же,
# как и с time.sleep(), просто по другой причине.
Любая тяжёлая по времени операция внутри callback — не только time.sleep() — занимает событийный цикл на всё это время. Для по-настоящему долгих задач: разбивать работу на части, планируемые через after(), или выносить в отдельный поток/процесс с безопасной передачей результата обратно — это уже продвинутая тема, не требующая полной реализации в этом курсе.
def obrabotat_chast(indeks):
if indeks >= len(dannye):
label.config(text="Готово")
return
obrabotat_odnu_zapis(dannye[indeks])
root.after(0, obrabotat_chast, indeks + 1) # следующая часть — на следующем такте цикла
Тестируем то, что можно протестировать без окна
def test_calculate_tip():
assert calculate_tip(100, 10, 2) == 5.0
test_calculate_tip()
print("Доменная логика проверена без единого виджета.")