Tkinter: графический интерфейс на Python
Tkinter в Python с нуля: первое окно, кнопки и поля ввода, размещение через pack и grid, обработчики событий, mainloop и установка python3-tk на Linux.
Содержание · 8 разделов
- Установка и проверка Tkinter
- Окно и mainloop
- Основные виджеты
- Переменные Tkinter
- Виджеты ttk
- Размещение виджетов: pack и grid
- Обработчики событий
- command у кнопок
- Пример: форма с grid и обработчиком
- bind: клавиши и мышь
- after: таймеры без зависания
- Частые ошибки
- Функция срабатывает сразу при запуске
- TclError при смешивании pack и grid
- Виджет создан, но не виден
- TclError: no display name and no $DISPLAY environment variable
- Окно зависает при долгой операции
- Частые вопросы
- Как открыть окно по центру экрана?
- Как изменить шрифт, размер и цвет текста?
- Как удалить все виджеты из окна?
- Как показать картинку в окне?
- Как сделать из программы на Tkinter exe-файл?
- Итог
Tkinter — стандартная библиотека Python для создания графического интерфейса: окон, кнопок, полей ввода и списков. Она входит в поставку Python для Windows и macOS, поэтому ставить ничего не нужно. Минимальное приложение на python tkinter:
import tkinter as tk
root = tk.Tk() # главное окно
root.title("Привет, Tkinter")
root.geometry("300x150") # ширина x высота
label = tk.Label(root, text="Hello, world!", font=("Arial", 14))
label.pack(pady=20)
def on_click():
label.config(text="Кнопка нажата")
tk.Button(root, text="Нажми меня", command=on_click).pack()
root.mainloop() # запустить цикл обработки событий
Ниже разберём, из чего состоит приложение на Tkinter: окно, виджеты, размещение через pack и grid, обработчики событий и mainloop, а также установку на Linux и частые ошибки. Примеры проверены на Python 3.12 с Tk 8.6.
Установка и проверка Tkinter
На Windows Tkinter устанавливается вместе с Python из официального установщика (пункт «tcl/tk and IDLE» включён по умолчанию). На macOS он есть в установщике с python.org; для Python из Homebrew нужен отдельный пакет brew install python-tk — он соответствует основной версии python в Homebrew, для другой версии указывайте её явно, например brew install python-tk@3.14.
Через pip Tkinter не ставится — такого пакета на PyPI нет:
pip install tkinter
# ERROR: No matching distribution found for tkinter
На Linux Tkinter часто вынесен в отдельный системный пакет. Если импорт падает с ModuleNotFoundError: No module named 'tkinter', установите его менеджером пакетов дистрибутива:
# Debian, Ubuntu, Mint
sudo apt install python3-tk
# Fedora
sudo dnf install python3-tkinter
# Arch Linux
sudo pacman -S tk
Проверить установку можно двумя способами:
python3 -m tkinter # откроется тестовое окно с версией Tk (на Windows — py -m tkinter)
import tkinter as tk
print(tk.TkVersion) # → 8.6
Если Python собран вручную или через pyenv без библиотек Tk, ошибка будет No module named '_tkinter' — тогда нужно поставить пакет разработки Tk (например, tk-dev в Debian/Ubuntu) и пересобрать Python. Общий разбор этой ошибки — в статье про ModuleNotFoundError.
Окно и mainloop
Любое приложение начинается с главного окна tk.Tk() и заканчивается вызовом mainloop():
root.title("...")— заголовок окна;root.geometry("400x300")— размер; можно указать и позицию:"400x300+100+50";root.resizable(False, False)— запретить изменение размера;root.destroy()— закрыть окно и выйти изmainloop().
mainloop() — бесконечный цикл: он ждёт действий пользователя (клик, нажатие клавиши, перерисовка) и вызывает ваши функции. Код после mainloop() выполнится только после закрытия окна. Без этого вызова окно в скрипте мелькнёт и сразу исчезнет.
Основные виджеты
Виджет — элемент интерфейса. Первым аргументом ему передают родителя (окно или рамку), остальные параметры задают текст, размер и поведение.
| Виджет | Назначение |
|---|---|
Label | текст или картинка |
Button | кнопка, функция — в параметре command |
Entry | однострочное поле ввода |
Text | многострочный текст |
Checkbutton | флажок |
Radiobutton | переключатель — один вариант из нескольких |
Listbox | список строк |
Scale | ползунок |
Frame | контейнер для группировки виджетов |
ttk.Combobox | выпадающий список |
Параметры уже созданного виджета меняют методом config(), а читают через cget() или как словарь:
label.config(text="Новый текст", fg="red")
print(label["text"]) # → Новый текст
Поле Entry читают методом get(), очищают — delete(0, tk.END), заполняют — insert(0, "текст"). У Text индексы вида "строка.символ", начиная с "1.0":
text = tk.Text(root, height=3, width=20)
text.insert("1.0", "строка 1\nстрока 2")
print(repr(text.get("1.0", tk.END))) # → 'строка 1\nстрока 2\n'
Text всегда добавляет в конец перевод строки — уберите его через .strip() или читайте до "end-1c".
Переменные Tkinter
Флажки, переключатели и надписи удобно связывать со специальными переменными StringVar, IntVar, BooleanVar. Значение читают get(), меняют set(), а виджет обновляется сам:
remember = tk.BooleanVar()
tk.Checkbutton(root, text="Запомнить меня", variable=remember).pack()
theme = tk.StringVar(value="light")
tk.Radiobutton(root, text="Светлая", variable=theme, value="light").pack()
tk.Radiobutton(root, text="Тёмная", variable=theme, value="dark").pack()
print(remember.get(), theme.get()) # → False light
Виджеты ttk
Модуль tkinter.ttk содержит те же виджеты (ttk.Button, ttk.Label, ttk.Entry) в оформлении текущей ОС и несколько дополнительных: Combobox, Progressbar, Treeview, Notebook. Внешний вид у них настраивается через стили, а не параметрами bg и fg.
from tkinter import ttk
combo = ttk.Combobox(root, values=["Python", "Django", "FastAPI"], state="readonly")
combo.current(0)
combo.pack()
print(combo.get()) # → Python
Размещение виджетов: pack и grid
Созданный виджет не появится в окне, пока вы не вызовете менеджер геометрии.
pack() складывает виджеты друг за другом — по умолчанию сверху вниз. Подходит для простых окон и панелей:
frame = tk.Frame(root, padx=10, pady=10)
frame.pack(fill="both", expand=True)
tk.Button(frame, text="OK").pack(side="left", padx=5)
tk.Button(frame, text="Отмена").pack(side="right")
Параметры: side ("top", "bottom", "left", "right"), fill ("x", "y", "both"), expand=True — занять свободное место, padx/pady — отступы.
grid() размещает виджеты по таблице строк и столбцов — это удобно для форм:
row,column— ячейка;columnspan,rowspan— объединение ячеек;sticky— прижать к краям ячейки:"w"(влево),"e","nsew"(растянуть);root.columnconfigure(0, weight=1)— столбец растягивается вместе с окном.
Есть и третий менеджер, place(), — он ставит виджет по точным координатам x и y, но при изменении размера окна такая вёрстка «ломается».
Важно: внутри одного контейнера нельзя смешивать
packиgrid. Нужно и то и другое — разделите окно наFrameи в каждом используйте один менеджер.
Обработчики событий
command у кнопок
Самый простой обработчик — функция в параметре command. Передавайте саму функцию, без скобок. Если нужны аргументы, оберните вызов в lambda:
tk.Button(root, text="Сохранить", command=save) # правильно
tk.Button(root, text="Удалить 5", command=lambda: delete_item(5)) # с аргументом
Пример: форма с grid и обработчиком
Небольшое приложение складывает два числа и показывает ошибку, если введены не числа:
import tkinter as tk
from tkinter import messagebox
root = tk.Tk()
root.title("Сумма")
tk.Label(root, text="Первое число:").grid(row=0, column=0, sticky="w", padx=5, pady=5)
tk.Label(root, text="Второе число:").grid(row=1, column=0, sticky="w", padx=5, pady=5)
entry_a = tk.Entry(root, width=10)
entry_a.grid(row=0, column=1, padx=5, pady=5)
entry_b = tk.Entry(root, width=10)
entry_b.grid(row=1, column=1, padx=5, pady=5)
result = tk.StringVar(value="Результат: —")
def calculate():
try:
total = float(entry_a.get()) + float(entry_b.get())
except ValueError:
messagebox.showerror("Ошибка", "Введите числа")
return
result.set(f"Результат: {total}")
tk.Button(root, text="Сложить", command=calculate).grid(row=2, column=0, columnspan=2, pady=5)
tk.Label(root, textvariable=result).grid(row=3, column=0, columnspan=2)
root.bind("<Return>", lambda event: calculate()) # Enter тоже запускает расчёт
root.mainloop()
Если ввести 2 и 3.5, надпись сменится на «Результат: 5.5». Диалоги messagebox (showinfo, showwarning, showerror, askyesno) открываются модальным окном; askyesno возвращает True или False. Перехват исключения разобран в статье про try/except.
bind: клавиши и мышь
Метод bind() связывает событие с функцией. Функция получает объект event с подробностями: event.keysym — имя клавиши, event.x и event.y — координаты курсора.
def on_key(event):
print("Нажата клавиша:", event.keysym)
entry = tk.Entry(root)
entry.pack()
entry.bind("<KeyRelease>", on_key) # отпускание клавиши в поле
root.bind("<Escape>", lambda e: root.destroy())
canvas = tk.Canvas(root, width=200, height=100, bg="white")
canvas.pack()
canvas.bind("<Button-1>", lambda e: print(e.x, e.y)) # клик левой кнопкой
Частые события: <Button-1> (левая кнопка мыши), <Double-Button-1>, <Return>, <Escape>, <KeyPress>, <Motion>.
after: таймеры без зависания
Обработчики выполняются в том же потоке, что и mainloop(). Пока функция работает, окно не перерисовывается и «зависает». Для периодических действий используйте root.after(миллисекунды, функция) вместо time.sleep():
import time
clock = tk.Label(root, font=("Arial", 24))
clock.pack()
def tick():
clock.config(text=time.strftime("%H:%M:%S"))
root.after(1000, tick) # запланировать следующий вызов через секунду
tick()
Долгие операции (сеть, большие файлы) выносите в отдельный поток, а результат передавайте в интерфейс через after(): менять виджеты Tkinter из других потоков нельзя.
Частые ошибки
Функция срабатывает сразу при запуске
tk.Button(root, text="Нажми", command=hello()) # ошибка: скобки
Со скобками hello() вызывается при создании кнопки, а в command попадает её результат (None). Уберите скобки или используйте lambda.
TclError при смешивании pack и grid
_tkinter.TclError: cannot use geometry manager grid inside . which already has slaves managed by pack
В одном контейнере (здесь . — главное окно) использованы оба менеджера. Оставьте один или разнесите виджеты по разным Frame.
Виджет создан, но не виден
Не вызван pack(), grid() или place(). Ещё одна ловушка — цепочка entry = tk.Entry(root).grid(...): grid() возвращает None, и в entry окажется None. Создавайте виджет и размещайте его отдельными строками.
TclError: no display name and no $DISPLAY environment variable
Ошибка _tkinter.TclError с таким текстом появляется на сервере или в Docker без графической среды. Tkinter нужен экран: запускайте программу на компьютере с рабочим столом или используйте виртуальный дисплей (например, Xvfb).
Окно зависает при долгой операции
Обработчик кнопки выполняет долгую работу, и mainloop() не может обработать события. Разбейте работу на части через after() или вынесите её в поток.
Частые вопросы
Как открыть окно по центру экрана?
Размер экрана возвращают winfo_screenwidth() и winfo_screenheight(). Вычтите размер окна, поделите пополам и передайте отступы в geometry():
w, h = 400, 300
x = (root.winfo_screenwidth() - w) // 2
y = (root.winfo_screenheight() - h) // 2
root.geometry(f"{w}x{h}+{x}+{y}")
Как изменить шрифт, размер и цвет текста?
Шрифт задаётся кортежем «семейство, размер, стиль», цвет текста — параметром fg, фон — bg:
label = tk.Label(root, text="Заголовок", font=("Arial", 16, "bold"), fg="white", bg="#1f77b4")
Стиль может быть "bold", "italic" или "bold italic". У виджетов ttk параметров fg и bg нет — их цвет меняют через ttk.Style.
Как удалить все виджеты из окна?
Метод winfo_children() возвращает дочерние виджеты окна или рамки, destroy() удаляет каждый:
for widget in root.winfo_children():
widget.destroy()
Если нужно лишь временно скрыть виджет, вызовите pack_forget() или grid_remove() — потом его можно показать снова.
Как показать картинку в окне?
tk.PhotoImage в Tk 8.6 читает PNG и GIF. Сохраните ссылку на картинку в переменной, иначе сборщик мусора удалит её и вместо изображения останется пустое место:
img = tk.PhotoImage(file="bg.png")
label = tk.Label(root, image=img)
label.image = img # держим ссылку
label.place(x=0, y=0, relwidth=1, relheight=1) # картинка во всё окно, как фон
Для JPEG и изменения размера используйте Pillow: ImageTk.PhotoImage(Image.open("photo.jpg")).
Как сделать из программы на Tkinter exe-файл?
Соберите её через PyInstaller:
pip install pyinstaller
pyinstaller --onefile --windowed app.py
Готовый файл появится в папке dist. Флаг --windowed убирает чёрное окно консоли, --onefile собирает всё в один файл. Собирать нужно на той ОС, для которой предназначен файл: exe для Windows делают на Windows.
Итог
Приложение на Tkinter состоит из окна tk.Tk(), виджетов, размещённых через pack или grid, обработчиков в command и bind и вызова mainloop(). Если интерфейс нужен для своих скриптов, посмотрите идеи в статье про автоматизацию на Python. Для игр с графикой и анимацией лучше подходит Pygame, идеи первых программ с интерфейсом — в подборке проектов на Python. Другие популярные пакеты — в обзоре библиотек Python, полный справочник — в документации tkinter.
- #Python
- #Tkinter
- #GUI
- #Интерфейс