События
Программа с окнами всё время ждёт: клика, нажатия клавиши, движения мыши. Каждое такое действие — событие, и на него можно повесить свою функцию.
bind
def on_click(event):
print("клик в", event.x, event.y)
canvas.bind("<Button-1>", on_click) # левая кнопка мыши на холсте
root.bind("<Key>", on_key) # любая клавиша, пока окно в фокусе
entry.bind("<Return>", on_enter) # Enter в поле ввода
Функция-обработчик получает объект event. В отличие от command у кнопки, bind всегда передаёт этот аргумент — без него будет ошибка.
Основные события
| Событие | Когда |
|---|---|
<Button-1>, <Button-3> |
нажата левая / правая кнопка мыши |
<ButtonRelease-1> |
левая кнопка отпущена |
<B1-Motion> |
мышь двигается с зажатой левой кнопкой |
<Motion> |
мышь просто двигается |
<Double-Button-1> |
двойной щелчок |
<Key> |
любая клавиша |
<Return>, <Escape>, <a>, <Left> |
конкретная клавиша |
<Control-s> |
сочетание Ctrl+S |
Что лежит в event
event.x,event.y— координаты мыши внутри виджета;event.keysym— имя клавиши:a,A,plus,BackSpace,Return,KP_1(цифра на цифровом блоке);event.char— символ, который клавиша печатает:"+","1"; у служебных клавиш — пусто;event.state— какие модификаторы зажаты, набором битов.
Чтобы печатать то, что ввёл пользователь, берут char: у клавиши + имя plus, а у цифры справа — KP_2.
Модификаторы и биты
В event.state каждый модификатор занимает свой бит. На Windows: Shift — 1, CapsLock — 2, Control — 4, NumLock — 8, Alt — 0x20000. Проверка конкретного бита — побитовое И:
ctrl = event.state & 0x4
shift = event.state & 0x1
Сравнение event.state == 4 — частая ошибка: стоит включить NumLock, и состояние станет 12, хотя Ctrl зажат.
Перетаскивание
Перетаскивание собирают из трёх событий:
def press(event): # запомнить, что схватили и где
...
def motion(event): # сдвинуть на разницу с прошлой точкой
...
def release(event): # отпустить
...
canvas.bind("<ButtonPress-1>", press)
canvas.bind("<B1-Motion>", motion)
canvas.bind("<ButtonRelease-1>", release)
Двигать фигуру нужно на разницу между текущей и прошлой точкой мыши, а не ставить её угол в курсор — иначе фигура прыгает. На холсте Canvas для этого есть canvas.move(item, dx, dy), поднять фигуру над остальными — canvas.tag_raise(item), а найти фигуры под курсором — canvas.find_overlapping(x, y, x, y) (последняя в списке — верхняя).
Итог
widget.bind("<Событие>", f), иfполучаетevent;- мышь:
event.x,event.y; клавиатура:keysym(имя) иchar(символ); - модификаторы — биты в
event.state, проверка через&; - перетаскивание: press → motion (сдвиг на разницу) → release.