</>
Topic 5 of 6

Course materials are currently available in Russian only.

События

Программа с окнами всё время ждёт: клика, нажатия клавиши, движения мыши. Каждое такое действие — событие, и на него можно повесить свою функцию.

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.