Обработка событий и настройка окна / tkinter 4
Возможность реагировать на события — одна из базовых, но важных тем в приложениях с графическим интерфейсом. Именно она определяет, как пользователи смогут взаимодействовать с программой.
Нажимание клавиш на клавиатуре и клики по элементам мышью — базовые примеры событий, все из которых автоматически обрабатываются в некоторых классах 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("", self.print_event)
frame.bind("", self.print_event)
frame.bind("", self.print_event)
frame.bind("", self.print_event)
frame.bind("", self.print_event)
frame.bind("", 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("", self.print_type)
entry.bind("", 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 использует синтаксис .
Модификаторы являются опциональными и позволяют задать дополнительные комбинации для общего типа события:
- 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 , если до этого была привязка или + для добавления функции обратного вызова и сохранения старых.
Помимо описанных типов событий есть и другие, которые оказываются полезными в определенных сценариях: например, генерируется при уничтожении виджета, а — при изменении размера или положения.
Полный список событий доступен в документации Tcl/Tk.
Настройка иконки, названия и размера основного окна
Экземпляр Tk отличается от обычных виджетов тем, как он настраивается. Рассмотрим основные методы, которые позволяют настраивать внешний вид.
Этот кусок кода создает основное окно с заданными названием и иконкой. Его ширина — 400 пикселей, а высота — 200. Плюс, есть разделение в 10px по каждой оси к левому верхнему углу экрана.
Обработчик событий в питоне
Tkinter позволяет обрабатывать события виджетов. Для обработки распространенных и наболее используемых событий Tkinter предоставляет интерфейс команд. Например, для обработки нажатия на кнопку ее параметру command надо передать функцию, которая будет вызываться при нажатии на кнопку
def click(): print("Hello") btn = ttk.Button(text="Click", command=click)
Ряд виджетов также позволяют с помощью параметра command задать обработчик для одного из событий данного виджета.
Однако что, если мы хотим обрабатывать другие события виджета. Например, для кнопки обработать получение фокуса, или обработать нажатие клавиши клавиатуры? Для подобных ситуаций Tkinter предоставляет ряд встроенных событий. Наиболее распространенные из них:
- Activate : окно становится активным.
- Deactivate : окно становится неактивным.
- MouseWheel : прокрутка колеса мыши.
- KeyPress : нажатие клавиши на клавиатуре.
- KeyRelease : освобождение нажатой клавиши
- ButtonPress : нажатие кнопки мыши.
- ButtonRelease : освобождение кнопки мыши.
- Motion : движение мыши.
- Configure : изменение размера и положения виджета
- Destroy : удаление виджета
- FocusIn : получение фокуса
- FocusOut : потеря фокуса.
- Enter : указатель мыши вошел в пределы виджета.
- Leave : указатель мыши покинул виджет.
Привязка событий
Для привязки события к виджету применяется метод bind() :
В качестве первого параметра указывается обрабатываемое событие, а в качестве второго - функция, которая обрабатывает событие.
Например, обработаем события получения и потери фокуса для кнопки:
from tkinter import * from tkinter import ttk root = Tk() root.title("METANIT.COM") root.geometry("250x200") def entered(event): btn["text"] ="Entered" def left(event): btn["text"] ="Left" btn = ttk.Button(text="Click") btn.pack(anchor=CENTER, expand=1) btn.bind("", entered) btn.bind("", left) root.mainloop()
Название событие передается в угловных скобках, например, "" или "". Для события Enter (получение фокуса) определен обработчик-функция entered, которая изменяет текст кнопки:
def entered(event): btn["text"] ="Entered"
Стоит обратить внимание, что функция обработки события должна принимать в качестве параметра объект события - в примере выше параметр event, даже если он в самой функции не используется.
Событие потери фокуса связывыется с функцией left:
Кроме обычных событий некоторые виджеты Tkinter могут использовать виртуальные события или высокоуровневые события (выше были описаны низкоуровневые события), которые помещаются в двойные угловные скобки, например, событие выделения списка ">". Наиболее используемые виртуальные события будут рассмотрены в соответствующих темах про виджеты.
Шаблон события
В примере выше при привязке события указывалось только имя события например, "" или "". Но в реальности в угловых скобках указывается не просто имя события, а его шаблон. Шаблон события имеет следующую форму:
Модификаторы события
Часто используемые модификаторы:
- Alt : нажата клавиша Alt
- Control : нажата клавиша Ctrl
- Shift : нажата клавиша Shift
- Any : нажата любая клавиша
Клавиши
Также в шаблоне можно указать конкретные клавиши или комбинации. Некоторые из них:
- Alt_L : левая клавиша alt
- Alt_R : правая клавиша alt
- BackSpace : клавиша backspace
- Cancel : клавиша break
- Caps_Lock клавиша CapsLock
- Control_L : левая клавиша control
- Control_R : правая клавиша control
- Delete : клавиша Delete
- Down : клавиша ↓
- End : клавиша end
- Escape : клавиша esc
- Execute : клавиша SysReq
- F1 : клавиша F1
- F2 : клавиша F2
- Fi : функциональная клавиша Fi
- F12 : клавиша F12
- Home : клавиша home
- Insert : клавиша insert
- Left : клавиша ←
- Linefeed : клавиша Linefeed (control-J)
- KP_0 : клавиша 0
- KP_1 : клавиша 1
- KP_2 : клавиша 2
- KP_3 : клавиша 3
- KP_4 : клавиша 4
- KP_5 : клавиша 5
- KP_6 : клавиша 6
- KP_7 : клавиша 7
- KP_8 : клавиша 8
- KP_9 : клавиша 9
- KP_Add : клавиша +
- KP_Begin : центральная клавиша (5)
- KP_Decimal : клавиша точка ( . )
- KP_Delete : клавиша delete
- KP_Divide : клавиша /
- KP_Down : клавиша ↓
- KP_End : клавиша end
- KP_Enter : клавиша enter
- KP_Home : клавиша home
- KP_Insert : клавиша insert
- KP_Left : клавиша ←
- KP_Multiply : клавиша ×
- KP_Next : клавиша PageDown
- KP_Prior : клавиша PageUp
- KP_Right : клавиша →
- KP_Subtract : клавиша -
- KP_Up : клавиша ↑
- Next : клавиша PageDown
- Num_Lock : клавиша NumLock
- Pause : клавиша pause
- Print : клавиша PrintScrn
- Prior : клавиша PageUp
- Return : клавиша Enter
- Right : клавиша →
- Scroll_Lock : клавиша ScrollLock
- Shift_L : левая клавиша shift
- Shift_R : правая клавиша shift
- Tab : клавиша tab
from tkinter import * from tkinter import ttk root = Tk() root.title("METANIT.COM") root.geometry("250x200") def single_click(event): btn["text"] ="Single Click" def double_click(event): btn["text"] ="Double Click" btn = ttk.Button(text="Click") btn.pack(anchor=CENTER, expand=1) btn.bind("", single_click) btn.bind("", double_click) root.mainloop()
Здесь в шаблоне "" ButtonPress - название события - нажатие кнопки мыши, а "1" указывает на конкретную кнопку - левую кнопку мыши (например, 3 - представляет правую кнопку)
А в шаблоне "" добавляется модификатор Doubles , который указывает на двойное нажатие.
Глобальная регистрация события
В примерах выше обработка события устанавливалась для одного конкретного объекта - для одной кнопки. Но что, если у нас много кнопок и мы хотим, чтобы для всех была установлена привязка одного и тоже события с одной и той же функцией_обработчиком? В этом случае мы можем установить привязку события глобально ко всем объектам класса с помощью метода bind_class класса Tk:
from tkinter import * from tkinter import ttk clicks = 0 root = Tk() root.title("METANIT.COM") root.geometry("250x200") def clicked(event): global clicks clicks = clicks + 1 btn["text"] =f" Clicks" btn = ttk.Button(text="Click") btn.pack(anchor=CENTER, expand=1) # привязка события к кнопкам ttk.Button root.bind_class("TButton", "", clicked) root.mainloop()
В данном случае для кнопок для обработки двойного нажатия установаливается обработчик - функция clicked. Причем события привязывается к кнопкам из пакета tkinter.ttk, поэтому в качестве типа виджетов используется "TButton" (а не просто Button).
Удаление события
Для открепления события от виджета вызывается метод unbind() , в который передается шаблон события: