Скачайте код уроков с GitLab: https://gitlab.com/PythonRu/tkinter-uroki
Обработка событий с мыши и клавиатуры
Возможность реагировать на события — одна из базовых, но важных тем в приложениях с графическим интерфейсом. Именно она определяет, как пользователи смогут взаимодействовать с программой.
Нажимание клавиш на клавиатуре и клики по элементам мышью — базовые примеры событий, все из которых автоматически обрабатываются в некоторых классах Tkinter. Например, это поведение уже реализовано в параметре command
класса виджета Button
, который вызывает определенную функцию.
Некоторые события можно вызвать и без участия пользователя. Например, фокус ввода можно сместить с одного виджета на другой.
Выполнить привязку события к виджету можно с помощью метода bind
. Следующий пример привязывает некоторые события мыши к экземпляру Frame
:
import tkinter as tk
class App(tk.Tk):
def __init__(self):
super().__init__()
frame = tk.Frame(self, bg="green",
height=100, width=100)
frame.bind("<Button-1>", self.print_event)
frame.bind("<Double-Button-1>", self.print_event)
frame.bind("<ButtonRelease-1>", self.print_event)
frame.bind("<B1-Motion>", self.print_event)
frame.bind("<Enter>", self.print_event)
frame.bind("<Leave>", self.print_event)
frame.pack(padx=50, pady=50)
def print_event(self, event):
position = "(x={}, y={})".format(event.x, event.y)
print(event.type, "event", position)
if __name__ == "__main__":
app = App()
app.mainloop()
Все события обрабатываются методом класса print_event()
, который выводит тип события и положение мыши в консоли. Можете поэкспериментировать, нажимая на зеленую рамку мышью и двигая ею, пока она будет выводить сообщения события.
Следующий пример содержит виджет поля ввода и несколько привязок. Одна из них срабатывает в тот момент, когда фокус оказывается в виджете, а вторая — при нажатии кнопки:
import tkinter as tk
class App(tk.Tk):
def __init__(self):
super().__init__()
entry = tk.Entry(self)
entry.bind("<FocusIn>", self.print_type)
entry.bind("<Key>", self.print_key)
entry.pack(padx=20, pady=20)
def print_type(self, event):
print(event.type)
def print_key(self, event):
args = event.keysym, event.keycode, event.char
print("Знак: {}, Код: {}, Символ: {}".format(*args))
if __name__ == "__main__":
app = App()
app.mainloop()
В первую очередь программа выведет сообщение события FocusIn
. Это произойдет в тот момент, когда фокус окажется в виджете Entry. Можно убедиться также в том, что события срабатывают и в случае с непечатаемыми символами, такими как клавиши стрелок или Backspace.
Как работает отслеживание событий
Метод bind
определен в классе widget
и принимает три аргумента: событие sequence
, функцию callback
и опциональную строку add
:
widget.bind(sequence, callback, add='')
Строка sequence
использует синтаксис <modifier-type-detail>
.
Модификаторы являются опциональными и позволяют задать дополнительные комбинации для общего типа события:
- Shift – когда пользователь нажимает клавишу Shift.
- Alt – когда пользователь нажимает клавишу Alt.
- Control – когда пользователь нажимает клавишу Control.
- Lock – когда пользователь нажимает клавишу Lock.
- Shift – когда пользователь нажимает клавишу Shift.
- Shift – когда пользователь нажимает клавишу Shift lock.
- Double – когда событие происходит дважды подряд.
- Triple – когда событие происходит трижды подряд.
Типы события определяют общий тип события:
- ButtonPress или Button – события, которые генерируются при нажатии кнопки мыши.
- ButtonRelease – событие, когда кнопка мыши отпускается.
- Enter – событие при перемещении мыши на виджет.
- Leave – событие, когда мышь покидает область виджета.
- FocusIn – событие, когда фокус ввода попадает в виджет.
- FocusOut – событие, когда виджет теряет фокус ввода.
- KeyPress или Key – событие для нажатия кнопки.
- KeyRelease – событие для отпущенной кнопки.
- Motion – событие при перемещении мыши.
detail
– также опциональный параметр, который отвечает за определение конкретной клавиши или кнопки:
- Для событий мыши 1 — это левая кнопка, 2 — средняя, а 3 — правая
- Для событий клавиатуры используются сами клавиши. Если это специальные клавиши, то используется специальный символ: enter, Tab, Esc, up, down, right, left, Backspace и функциональные клавиши (от F1 до F12).
Функция callback
принимает параметр события. Для событий мыши это следующие атрибуты:
x
иy
– текущее положение мыши в пикселяхx_root
иy_root
— то же, что и x или y, но относительно верхнего левого угла экранаnum
– номер кнопки мыши
Для клавиш клавиатуры это следующие атрибуты:
char
– нажатая клавиша в виде строкиkeysym
– символ нажатой клавишиkeycode
– код нажатой клавиши
В обоих случаях у события есть атрибут widget
, ссылающийся на экземпляр, который сгенерировал событие и type
, определяющий тип события.
Рекомендуется определять метод для функции
callback
, поскольку всегда будет иметься ссылка на экземпляр класса, и таким образом можно будет легко получить доступ к атрибутамwidget
.
Наконец, параметр add
может быть пустым (""
) для замены функции callback
, если до этого была привязка или +
для добавления функции обратного вызова и сохранения старых.
Помимо описанных типов событий есть и другие, которые оказываются полезными в определенных сценариях: например, <Destroy>
генерируется при уничтожении виджета, а <Configure>
— при изменении размера или положения.
Полный список событий доступен в документации Tcl/Tk.
Настройка иконки, названия и размера основного окна
Экземпляр Tk отличается от обычных виджетов тем, как он настраивается. Рассмотрим основные методы, которые позволяют настраивать внешний вид.
Этот кусок кода создает основное окно с заданными названием и иконкой. Его ширина — 400 пикселей, а высота — 200. Плюс, есть разделение в 10px по каждой оси к левому верхнему углу экрана.
import tkinter as tk
class App(tk.Tk):
def __init__(self):
super().__init__()
self.title("Моя программа")
self.iconbitmap("python.ico")
self.geometry("400x200+10+10")
if __name__ == "__main__":
app = App()
app.mainloop()
Программа предполагает, что есть валидный ICO-файл python.ico в той же директории, где находится и сам скрипт. Вот результат:
Как работает настройка окна
Названия методов title()
и iconbitmap()
класса Tk говорят сами за себя. Первый настраивает название окна, а второй — принимает путь к иконке для него.
Метод geometry()
настраивает размер окна с помощью строки со следующим шаблоном:
{width}x{height}+{of set_x}+{of set_y}
Если в приложении есть дополнительные окна, то эти же методы доступны в классе Toplevel
.
Чтобы сделать приложение полноэкранным, нужно заменить вызов метода geometry()
на self.state("zoomed")
.