Основная черта любой программы с графическим интерфейсом - интерактивность. Программа не просто что-то считает (в пакетном режиме) от начала своего запуска до конца: ее действия зависят от вмешательства пользователя. Фактически, графическое приложение выполняет бесконечный цикл обработки событий. Программа, реализующая графический интерфейс, событийно-ориентирована. Она ждет от интерфейса событий, которые и обрабатывает сообразно своему внутреннему состоянию.
Эти события возникают в элементах графического интерфейса (виджетах) и обрабатываются прикрепленными к этим виджетам обработчиками. Сами виджеты имеют многочисленные свойства (цвет, размер, расположение), выстраиваются в иерархию принадлежности (один виджет может быть хозяином другого), имеют методы для доступа к своему состоянию.
Расположением виджетов (внутри других виджетов) ведают так называемые менеджеры расположения. Виджет устанавливается на место по правилам менеджера расположения. Эти правила могут определять не только координаты виджета, но и его размеры. В Tk имеются три типа менеджеров расположения: простой упаковщик (pack), сетка (grid) и произвольное расположение (place).
Но этого для работы графической программы недостаточно. Дело в том, что некоторые виджеты в графической программе должны быть взаимосвязаны определенным образом. Например, полоска прокрутки может быть взаимосвязана с текстовым виджетом: при использовании полоски текст в виджете должен двигаться, и наоборот, при перемещении по тексту полоска должна показывать текущее положение. Для связи между виджетами в Tk используются переменные, через которые виджеты и передают друг другу параметры.
Для построения графического интерфейса в библиотеке Tk отобраны следующие классы виджетов (в алфавитном порядке):
Все эти классы не имеют отношений наследования друг с другом - они равноправны. Этот набор достаточен для построения интерфейса в большинстве случаев.
В системе современного графического интерфейса имеется возможность отслеживать различные события, связанные с клавиатурой и мышью, и происходящие на "территории" того или иного виджета. В Tk события описываются в виде текстовой строки - шаблона события, состоящего из трех элементов (модификаторы, тип события и детализация события).
Примеры описаний событий строками и некоторые названия клавиш приведены ниже:
"<ButtonPress-3>" или просто "<3>" - щелчок правой кнопки мыши (то есть, третьей, если считать на трехкнопочной мыши слева-направо). "<Shift-Double-Button-1>" - двойной щелчок мышью (левой кнопкой) с нажатой кнопкой Shift. В качестве модификаторов могут быть использованы следующие (список неполный):
Control, Shift, Lock, Button1-Button5 или B1-B5, Meta, Alt, Double, Triple.
Просто символ обозначает событие - нажатие клавиши. Например, "k" - тоже, что "<KeyPress-k>". Для неалфавитно-цифровых клавиш есть специальные названия:
Cancel, BackSpace, Tab, Return, Shift_L, Control_L, Alt_L, Pause, Caps_Lock, Escape, Prior, Next, End, Home, Left, Up, Right, Down, Print, Insert, Delete, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, Num_Lock, Scroll_Lock, space, less
Здесь <space> обозначает пробел, а <less> - знак меньше. <Left>, <Right>, <Up>, <Down> - стрелки. <Prior>, <Next> - это PageUp и PageDown. Остальные клавиши более или менее соответствуют надписям на стандартной клавиатуре.
Примечание:
Следует заметить, что Shift_L, в отличие от Shift, нельзя использовать как модификатор.
В конкретной среде комбинации, означающие что-то особенное в системе, могут не дойти до графического приложения. Например, известный всем Ctrl-Alt-Del.
Следующая программа позволяет печатать направляемые виджету события, в частности - keysym, а также анализировать, как различные клавиши можно представить в шаблоне события:
from Tkinter import * tk = Tk() # основное окно приложения txt = Text(tk) # текстовый виджет, принадлежащий окну tk txt.pack() # располагается менеджером pack # функция обработки события def event_info(event): txt.delete("1.0", END) # удаляется с начала до конца текста for k in dir(event): # цикл по атрибутам события if k[0] != "_": # берутся только неслужебные атрибуты # готовится описание атрибута события ev = "%15s: %s\n" % (k, repr(getattr(event, k))) txt.insert(END, ev) # добавляется в конец текста # привязывается виджету txt функция event_info для обработки событий, # соответствующих шаблону <KeyPress> txt.bind("<KeyPress>", event_info) tk.mainloop() # главный цикл обработки событий
При нажатии клавиши Esc в окне можно увидеть примерно следующее:
char: '\x1b' delta: 9 height: 0 keycode: 9 keysym: 'Escape' keysym_num: 65307 num: 9 send_event: False serial: 159 state: 0 time: -1072960858 type: '2' widget: <Tkinter.Text instance at 0x401e268c> width: 0 x: 83 x_root: 448 y: 44 y_root: 306
Следует объяснить некоторые из этих атрибутов:
В принципе, совсем необязательно, чтобы события обрабатывал тот же виджет, который их первично принял. Например, можно перенаправить все события внутри подчиненных виджетов на данный виджет с помощью метода grab_set() ( grab_release() освобождает виджет от этой обязанности). В Tk существуют и другие возможности управления событиями, которые можно изучить по документации.