Обработка событий и настройка окна / tkinter 4

Скачайте код уроков с 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:

Строка 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 в той же директории, где находится и сам скрипт. Вот результат:

настройка окна Tkinter

Как работает настройка окна

Названия методов title() и iconbitmap() класса Tk говорят сами за себя. Первый настраивает название окна, а второй — принимает путь к иконке для него.

Метод geometry() настраивает размер окна с помощью строки со следующим шаблоном:

{width}x{height}+{of set_x}+{of set_y}

Если в приложении есть дополнительные окна, то эти же методы доступны в классе Toplevel.

Чтобы сделать приложение полноэкранным, нужно заменить вызов метода geometry() на self.state("zoomed").

Максим
Я создал этот блог в 2018 году, чтобы распространять полезные учебные материалы, документации и уроки на русском. На сайте опубликовано множество статей по основам python и библиотекам, уроков для начинающих и примеров написания программ.
Мои контакты: Почта
admin@pythonru.comAlex Zabrodin2018-10-26OnlinePython, Programming, HTML, CSS, JavaScript