События в Tkinter и их обработка
Обычно, чтобы приложение с графическим интерфейсом что-то делало, должны происходить те или иные события, чаще всего представляющие собой воздействие человека на элементы GUI.
Можно выделить три основных типа событий: производимые мышью, нажатиями клавиш на клавиатуре, а также события, возникающие в результате изменения виджетов. Нередко обрабатываются сочетания. Например, клик мышью с зажатой клавишей на клавиатуре.
При вызове метода bind
событие передается в качестве первого аргумента.
Название события заключается в кавычки, а также уже внутри кавычек в угловые скобки <
и >
. События описывается с помощью зарезервированных ключевых слов.
Часто используемые события, производимые мышью:
-
<Button-1>
– клик левой кнопкой мыши -
<Button-2>
– клик средней кнопкой мыши -
<Button-3>
– клик правой кнопкой мыши -
<Double-Button-1>
– двойной клик левой кнопкой мыши -
<Motion>
– движение мыши
Пример:
from tkinter import * def b1(event): root.title('Левая кнопка мыши') def b3(event): root.title('Правая кнопка мыши') def move(event): x = event.x y = event.y s = 'Движение мышью {}x{}'.format(x, y) root.title(s) root = Tk() root.minsize(width=500, height=400) root.bind('<Button-1>', b1) root.bind('<Button-3>', b3) root.bind('<Motion>', move) root.mainloop()
В этой программе меняется надпись в заголовке главного окна в зависимости от того, двигается мышь, щелкают левой или правой кнопкой.
Событие (Event
) – это один из объектов tkinter
. У событий есть атрибуты, как и у многих других объектов. В примере в функции move
извлекаются значения атрибутов x
и y
объекта event, в которых хранятся координаты местоположения курсора мыши в пределах виджета, по отношению к которому было сгенерировано событие. В данном случае виджетом является главное окно, а событием – <Motion>
, т. е. перемещение мыши.
В программе ниже выводится информация об экземпляре Event
и некоторым его свойствам. Все атрибуты можно посмотреть с помощью команды dir(event)
. У разных событий они одни и те же, меняются только значения. Для тех или иных событий часть атрибутов не имеет смысла, такие свойства имеют значения по умолчанию.
В примере хотя обрабатывается событие нажатия клавиши клавиатуры, в поля x
, y
, x_root
, y_root
сохраняются координаты положения на экране курсора мыши.
from tkinter import * def event_info(event): print(type(event)) print(event) print(event.time) print(event.x_root) print(event.y_root) root = Tk() root.bind('a', event_info) root.mainloop()
Пример выполнения программы:
<class 'tkinter.Event'> <KeyPress event state=Mod2 keysym=a keycode=38 char='a' x=194 y=135> 15431809 244 249
Для событий с клавиатуры буквенные клавиши можно записывать без угловых скобок (например, 'a'
).
Для неалфавитных клавиш существуют специальные зарезервированные слова. Например, <Return>
- нажатие клавиши Enter, <space>
- пробел. (Заметим, что есть событие <Enter>
, которое не имеет отношения к нажатию клавиши Enter, а происходит, когда курсор заходит в пределы виджета.)
Рассмотрим программу:
from tkinter import * def enter_leave(event): if event.type == '7': event.widget['text'] = 'In' elif event.type == '8': event.widget['text'] = 'Out' root = Tk() lab1 = Label(width=20, height=3, bg='white') lab1.pack() lab1.bind('<Enter>', enter_leave) lab1.bind('<Leave>', enter_leave) lab2 = Label(width=20, height=3, bg='black', fg='white') lab2.pack() lab2.bind('<Enter>', enter_leave) lab2.bind('<Leave>', enter_leave) root.mainloop()
В ней две метки используют одну и ту же функцию, и каждая метка использует эту функцию для обработки двух разных событий: ввода курсора в пределы виджета и вывода во границы.
Функция, в зависимости от того, по отношению к какому виджету было зафиксировано событие, изменяет свойства только этого виджета. Как изменяет, зависит от произошедшего события.
Свойство event.widget
содержит ссылку на виджет, сгенерировавший событие. Свойство event.type
описывает, что это было за событие. У каждого события есть имя и номер. С помощью выражения print(repr(event.type))
можно посмотреть его полное описание. При этом на одних платформах str(event.type)
возвращает имя события (например, 'Enter'), на других – строковое представление номера события (например, '7').
Вернемся к событиям клавиатуры. Сочетания клавиш пишутся через тире. В случае использования так называемого модификатора, он указывается первым, детали на третьем месте. Например, <Shift-Up>
- одновременное нажатие клавиш Shift и стрелки вверх, <Control-B1-Motion>
– движение мышью с зажатой левой кнопкой и клавишей Ctrl.
from tkinter import * def exit_win(event): root.destroy() def to_label(event): t = ent.get() lbl.configure(text=t) def select_all(event): def select_all2(widget): widget.selection_range(0, END) widget.icursor(END) # курсор в конец root.after(10, select_all2, event.widget) root = Tk() ent = Entry(width=40) ent.focus_set() ent.pack() lbl = Label(height=3, fg='orange', bg='darkgreen', font='Verdana 24') lbl.pack(fill=X) ent.bind('<Return>', to_label) ent.bind('<Control-a>', select_all) root.bind('<Control-q>', exit_win) root.mainloop()
Здесь сочетание клавиш Ctrl+a выделяет текст в поле. Без root.after()
выделение не работает. Метод after
выполняет функцию, указанную во втором аргументе, через промежуток времени, указанный в первом аргументе. В третьем аргументе передается значение атрибута widget
объекта event. В данном случае им будет поле ent. Именно оно будет передано как аргумент в функцию select_all2 и присвоено параметру widget.
Практическая работа
Напишите программу по описанию. Размеры многострочного текстового поля определяются значениями, введенными в однострочные текстовые поля. Изменение размера происходит при нажатии мышью на кнопку, а также при нажатии клавиши Enter.
Цвет фона экземпляра Text
светлосерый (lightgrey
), когда поле не в фокусе, и белый, когда имеет фокус.
Событие получения фокуса обозначается как <FocusIn>
, потери – как <FocusOut>
.
Для справки: фокус перемещается по виджетам при нажатии Tab, Ctrl+Tab, Shift+Tab, а также при клике по ним мышью (к кнопкам последнее не относится).
Курс с примерами решений практических работ: pdf-версия