Глава 16 · Создаём классные приложения с Tkinter

Итоги главы: инструментарий Tkinter

От «программа ждёт событий, а не выполняется по порядку» до класса приложения с персистентными настройками.

Визуальный контакт-лист виджетов

Прежде чем выбирать по названию — вспомните, как это выглядит:

Глава 16 — контакт-лист
Label / Entry / Button
текст, поле ввода, кнопка
витрина виджетов
Checkbutton
независимый флажок
снят/установлен
Radiobutton
группа взаимоисключающих вариантов
выбран один из трёх
Combobox
выбор из выпадающего списка
открытый список
Listbox
список с выделением элемента
выделенный элемент
Spinbox / Scale
число со стрелками / ползунок
Spinbox
Scale
Progressbar
индикатор выполнения
0–100%
Notebook
переключаемые вкладки
три вкладки
Toplevel
отдельное второе окно
главное + настройки
🔶 Схематическое изображение (не реальный скриншот)
Файл
Правка
Новый
Открыть...
Выход

Инструментарий Tkinter

Что выбрать для конкретной задачи
Нужно главное окно приложения
tk.Tk() — один на процесс
Нужно ещё одно окно
tk.Toplevel(root)
Нужен тематизированный виджет формы
ttk.Label/Button/Entry/Combobox/...
Нужен многострочный редактор
tk.Text / ScrolledText
Простое вертикальное расположение
pack()
Форма/таблица/адаптивные колонки
grid() + weight/sticky
Точное позиционирование
place() — осознанно
Общее состояние нескольких виджетов
StringVar/IntVar/BooleanVar/DoubleVar
Уведомление пользователя
messagebox
Выбор файла
filedialog + pathlib
Отложенный/повторяющийся вызов без блокировки
root.after(...)
Персистентные настройки
JSON + pathlib (глава 15)
Структура крупного приложения
класс App + мелкие callback + чистая логика
Обработка клавиатуры/мыши напрямую
глава 17 — .bind(...)
Глава 16 целиком
Событийная модель
mainloop() — цикл, а не заморозка
callback ≠ command ≠ event
function без скобок
Дерево виджетов
родитель определяет контекст
create → configure → размещение → интерактивность
tk и ttk
ttk — тема + современные виджеты
стиль через ttk.Style(), не fg/bg
Компоновка
pack — простые регионы
grid + weight — адаптивные формы
не смешивать в одном родителе
Ввод и состояние
Entry/Text, end-1c
Tk-переменные ≠ замена Python-переменных
Диалоги и окна
messagebox/filedialog — проверяйте результат
Toplevel, не второй Tk()
Отзывчивость
after() вместо sleep()
долгая работа — не в одном callback
Архитектура
чистая логика отдельно от виджетов
App HAS-A root
настройки — через JSON главы 15
Tkinter-приложение
Событийная модель
mainloop
callback/command
Интерфейс
дерево виджетов
tk/ttk
pack/grid/place
Данные
Tk-переменные
валидация
Диалоги
messagebox
filedialog
Toplevel
Отзывчивость
after()
не sleep()
Архитектура
класс приложения
персистентные настройки
Карта главы 16 целиком.

Последовательное внутри событийного

Точная формулировка важнее эффектной: инициализационный код по-прежнему выполняется последовательно, строка за строкой — и каждый отдельный callback тоже выполняется последовательно, когда его вызывают. Меняется не это, а общая модель управления: именно событийный цикл решает, какой callback будет вызван следующим, в ответ на событие — а не сам код, идущий одной сплошной линией сверху вниз.

старт программы
инициализация
выполняется последовательно
строка за строкой
mainloop()
событие → выбрал цикл
callback A
тоже выполняется
последовательно
следующее событие → снова выбрал цикл
callback B
тоже выполняется
последовательно
Последовательность никуда не делась — она просто разбита на куски, между которыми решает событийный цикл.

Что дальше

Мы теперь умеем: строить root и дерево виджетов, связывать callback через command, компоновать формы через pack и адаптивный grid, хранить общее состояние в Tk-переменных, показывать диалоги, открывать/сохранять файлы, планировать отложенные вызовы через after() и собирать всё в класс приложения с персистентными настройками.

В главе 17 («Проект: игра «Крестики-нолики» с Tkinter») мы построим полноценную игру — и познакомимся с более общим механизмом привязки событий, .bind("<Button-1>", ...), который реагирует на клик в любом месте виджета (например, на конкретную клетку холста), а не только на предопределённое действие вроде command у кнопки.

Что мы узнали в этой главе

  • Инициализация и каждый callback по-прежнему выполняются последовательно — меняется общая модель управления: событийный цикл решает, какой callback вызвать следующим, в ответ на события.
  • root.mainloop() запускает цикл обработки событий, а не «замирает» — программа остаётся отзывчивой.
  • command=функция связывает callback с виджетом — без скобок после имени функции.
  • Каждый виджет создаётся, настраивается и отдельно размещается менеджером геометрии — pack(), grid() или place(), но не смешивая pack/grid в одном родителе.
  • ttk даёт тематизированные виджеты и стилизацию через ttk.Style() — но не заменяет tk.Text/Canvas/Menu.
  • Tk-переменные (StringVar и другие) связывают несколько виджетов с одним значением — и не заменяют обычные переменные Python.
  • messagebox и filedialog возвращают реальные значения, которые нужно проверять (в том числе на отмену), а не предполагать.
  • after() планирует отложенный или повторяющийся вызов без блокировки — time.sleep() в callback замораживает весь интерфейс.
  • Доменную логику стоит писать как чистые функции, проверяемые без единого виджета — callback лишь читает ввод, вызывает логику и обновляет экран.
  • Персистентные настройки GUI-приложения используют те же функции JSON+pathlib, что и глава 15 — ничего принципиально нового.