Модуль tkinter: создание оконных приложений на Python

Раздел: Основы Python -> Работа с модулями

Основы работы с модулем tkinter

Основное решение: создание простого окна

tkinter - стандартная библиотека Python для создания графических интерфейсов. Первый шаг - импорт модуля и создание главного окна. Минимальный код:

import tkinter as tk

root = tk.Tk()  # создаем главное окно
root.mainloop()  # запускаем цикл обработки событий

Python module attributes (атрибуты модуля в python)

После вызова mainloop() окно остается открытым до закрытия пользователем. Без этого вызова окно мгновенно закроется.

Типичная ошибка: забыть вызвать mainloop() - окно не появится. Еще одна проблема: повторный импорт модуля с переопределением имени - избегайте конфликтов.

Как создать окно с заданным размером и заголовком?

Методы geometry и title позволяют настроить окно:

import tkinter as tk

root = tk.Tk()
root.title("Мое приложение")  # заголовок
root.geometry("400x300+100+50")  # ширина x высота + смещение от левого края + от верхнего
root.mainloop()

Python module version (версия модуля python)

Формат строки: "widthxheight+x+y". Если не указать смещение, окно появится в центре экрана (по умолчанию).

Ошибка: неверный формат (например, пробелы вместо x) вызывает исключение TclError. Проверяйте строку.

Как добавить кнопку и обработать нажатие?

Виджет Button создает кнопку. Параметр command связывает функцию с событием клика:

import tkinter as tk

def say_hello():
    print("Привет!")

root = tk.Tk()
btn = tk.Button(root, text="Нажми меня", command=say_hello)
btn.pack()  # размещаем кнопку
root.mainloop()

Python cpp module (взаимодействие python с модулями c++)

Функция say_hello выполняется при каждом нажатии. Чтобы передать аргументы, используют lambda или functools.partial.

Проблема: если передать command=func() (с круглыми скобками), функция выполнится один раз при создании кнопки, а не по клику. Всегда используйте ссылку на функцию без скобок или обертку lambda.

Как разместить несколько виджетов с помощью pack, grid, place?

Три менеджера геометрии: pack (упаковка в контейнер), grid (сетка), place (абсолютное позиционирование). Пример с grid:

import tkinter as tk

root = tk.Tk()

tk.Label(root, text="Имя:").grid(row=0, column=0)
tk.Entry(root).grid(row=0, column=1)
tk.Button(root, text="Войти").grid(row=1, columnspan=2)

root.mainloop()

Python module cv2 (модуль cv2 (opencv) в python)

Строки и столбцы нумеруются с 0. columnspan объединяет ячейки. Менеджеры не должны смешиваться для одного родительского виджета - это вызовет ошибку.

Типичная ошибка: использовать одновременно pack и grid для разных виджетов с одним родителем - программа зависает или выдает исключение. Выбирайте один способ на контейнер.

Как создать текстовое поле и получить введенный текст?

Виджет Entry для однострочного ввода. Чтобы получить текст, используется метод get():

import tkinter as tk

def show_text():
    content = entry.get()
    print(f"Вы ввели: {content}")

root = tk.Tk()
entry = tk.Entry(root)
entry.pack()
btn = tk.Button(root, text="Показать", command=show_text)
btn.pack()
root.mainloop()

Python encodings module (модуль encodings в python)

Если поле пустое, get() вернет пустую строку. Для многострочного текста используют Text и get("1.0", "end-1c").

Ошибка: попытка получить текст до того, как окно создано - виджет уже существует, но пользователь еще не ввел данные. Логично вызывать get() только по событию (например, нажатию кнопки).

Как создать метку и изменить ее текст?

Label отображает статический или динамический текст. Для обновления используйте метод config или label["text"] = ...:

import tkinter as tk

def update_label():
    label.config(text="Текст изменен")

root = tk.Tk()
label = tk.Label(root, text="Исходный текст")
label.pack()
btn = tk.Button(root, text="Изменить", command=update_label)
btn.pack()
root.mainloop()

Метка может содержать не только текст, но и изображения (параметр image). Для обновления картинки потребуется пересоздать объект PhotoImage.

Проблема: если изменить текст до запуска mainloop(), окно все равно отобразится с новым текстом. Однако стандартная практика - изменять виджеты во время работы приложения через события.

- Module sys python (модуль sys в python)
- Python tkinter module (модуль tkinter в python)
- Python types module (модуль types в python)

Расширенные примеры использования tkinter

Рисование на холсте (Canvas)

Виджет Canvas позволяет рисовать линии, фигуры, текст и изображения. Пример создания простой анимации круга:

Пример
import tkinter as tk

def move_ball():
    canvas.move(ball, 2, 0)  # сдвигаем мяч на 2 пикселя вправо
    root.after(50, move_ball)  # повторяем через 50 мс

root = tk.Tk()
canvas = tk.Canvas(root, width=400, height=300, bg="white")
canvas.pack()
ball = canvas.create_oval(10, 10, 40, 40, fill="red")
move_ball()
root.mainloop()

Метод after планирует следующий вызов функции, создавая анимацию. Координаты фигур задаются как (x1, y1, x2, y2).

Красный круг плавно движется слева направо по белому холсту.

Таблица с использованием Treeview (ttk)

Виджет Treeview из модуля ttk (тематические виджеты) поддерживает таблицы с колонками и иерархические данные. Пример таблицы контактов:

Пример
import tkinter as tk
from tkinter import ttk

root = tk.Tk()
tree = ttk.Treeview(root, columns=("name", "phone"), show="headings")
tree.heading("name", text="Имя")
tree.heading("phone", text="Телефон")
tree.insert("", "end", values=("Иван", "+7-123-456-78-90"))
tree.insert("", "end", values=("Мария", "+7-098-765-43-21"))
tree.pack()
root.mainloop()

Параметр show="headings" скрывает пустой первый столбец (обычно используемый для иерархии). Для добавления строк используется insert с родительским элементом (пустая строка - корень).

Отображается таблица с двумя колонками и двумя строками.

Вкладки Notebook (ttk)

Виджет Notebook создает набор вкладок. Каждая вкладка содержит отдельный фрейм. Пример:

Пример
import tkinter as tk
from tkinter import ttk

root = tk.Tk()
notebook = ttk.Notebook(root)
notebook.pack(fill="both", expand=True)

frame1 = ttk.Frame(notebook)
frame2 = ttk.Frame(notebook)
notebook.add(frame1, text="Вкладка 1")
notebook.add(frame2, text="Вкладка 2")

ttk.Label(frame1, text="Содержимое первой вкладки").pack()
ttk.Label(frame2, text="Содержимое второй вкладки").pack()

root.mainloop()

Фреймы добавляются через add, параметр text задает заголовок вкладки. fill и expand растягивают виджет при изменении окна.

Окно с двумя вкладками, при переключении отображается соответствующее содержимое.

Работа с изображениями (PhotoImage)

tkinter поддерживает формат GIF и PNG (через PhotoImage, но PNG только в Python 3.11+). Для других форматов используют Pillow. Пример отображения изображения на метке:

Пример
import tkinter as tk

root = tk.Tk()
img = tk.PhotoImage(file="example.gif")  # замените на существующий файл
label = tk.Label(root, image=img)
label.pack()
root.mainloop()

Важно: переменная img должна жить, пока окно открыто. Если присвоить image в локальной переменной функции, изображение может не отобразиться (сборщик мусора). Решение - сохранить ссылку (например, в атрибуте виджета: label.image = img).

Метка отображает выбранное изображение из файла.

Создание собственного диалогового окна (Toplevel)

Виджет Toplevel создает дополнительное окно, независимое от главного. Пример окна с пользовательским вводом:

Пример
import tkinter as tk

def open_dialog():
    dialog = tk.Toplevel(root)
    dialog.title("Введите данные")
    tk.Label(dialog, text="Имя:").pack()
    entry = tk.Entry(dialog)
    entry.pack()
    def submit():
        print(f"Введено: {entry.get()}")
        dialog.destroy()
    tk.Button(dialog, text="OK", command=submit).pack()

root = tk.Tk()
tk.Button(root, text="Открыть диалог", command=open_dialog).pack()
root.mainloop()

Метод destroy закрывает дочернее окно. Если нужно сделать модальным (блокировать взаимодействие с главным окном), используйте grab_set().

При нажатии кнопки открывается новое окно, после ввода текста и нажатия OK данные выводятся в консоль.

Использование StringVar для автоматического обновления

Переменные tkinter (StringVar, IntVar и т.д.) позволяют синхронизировать значение между виджетами. Пример с меткой и полем ввода:

Пример
import tkinter as tk

root = tk.Tk()
var = tk.StringVar()

tk.Entry(root, textvariable=var).pack()
tk.Label(root, textvariable=var).pack()  # автоматически отображает введенный текст

root.mainloop()

Любое изменение в Entry немедленно меняет текст метки. Можно также подписаться на изменения через trace.

При вводе текста в поле он сразу дублируется в метке.

Привязка клавиш (bind) и событий мыши

Метод bind связывает любое событие (нажатие клавиши, движение мыши) с функцией-обработчиком. Пример обработки нажатия Enter в Entry:

Пример
import tkinter as tk

def on_enter(event):
    print("Нажат Enter")

root = tk.Tk()
entry = tk.Entry(root)
entry.pack()
entry.bind("", on_enter)  # событие Return - клавиша Enter
root.mainloop()

Событие передает объект event с информацией (координаты, код клавиши). Для мыши используют <Button-1> (левая кнопка), <Motion> (движение).

При нажатии Enter в поле ввода в консоль выводится сообщение.

Модуль tkinter в Python - comments

En
Python tkinter module (python)