Различия между версиями 1 и 2
Версия 1 от 2010-05-18 19:46:25
Размер: 22229
Редактор: alafin
Комментарий:
Версия 2 от 2010-05-18 19:54:31
Размер: 36513
Редактор: alafin
Комментарий:
Удаления помечены так. Добавления помечены так.
Строка 105: Строка 105:
== Как связать событие с обработчиком? ==

Биндеры состоят из объектов класса wx.!PyEventBinder. Объекты wx.!PyEventBinder определены для всех типов поддерживаемых событий. Вы можете создать ваши собственные биндеры для ваших собственных типов событий, когда это необходимо. Для каждого типа события определен свой биндер. Типы событий более детализированы чем подклассы wx.Event. Например, класс wx.MouseEvent имеет четырнадцать отдельных типов событий.

В wxPython, имена объектов биндеров глобальны. Чтобы ясно связать типы объектов с обработчиками, эти имена начинаются с wx.EVT_ и соответствуют названиям макроопределений, используемых в коде C++ wxWidgets. В коде wxPython, имя биндера используются вместо типа события. В результате, и это стоит подчеркнуть, имя биндера – это не целочисленный код, который вы получили бы, вызывая метод GetEventType() объекта wx.Event. Челочисленные коды типов событий имеют полностью различный набор глобальных названий, и не часто используются практически.

Для примера рассмотрим типы событий wx.MouseEvent. Как мы упоминали, их – четырнадцать. Девять из них описывают нажатия кнопок мыши. Вот их имена:
{{{#!highlight python
wx.EVT_LEFT_DOWN
wx.EVT_LEFT_UP
wx.EVT_LEFT_DCLICK
wx.EVT_MIDDLE_DOWN
wx.EVT_MIDDLE_UP
wx.EVT_MIDDLE_DCLICK
wx.EVT_RIGHT_DOWN
wx.EVT_RIGHT_UP
wx.EVT_RIGHT_DCLICK
}}}
Дополнительно, событие типа wx.!EVT_MOTION происходит при перемещении мыши. Собития типов wx.!ENTER_WINDOW и wx.!LEAVE_WINDOW возникают, когда курсор мыши входит в область виджета и выходит из нее. Событие типа wx.!EVT_MOUSEWHEEL происходит из-за движения колесика мыши. Наконец, вы можете связать все события мыши с единственной функцией, используя тип wx.!EVT_MOUSE_EVENTS.

Аналогично, класс wx.!CommandEvent имеет 28 различных типов событий, связанных с ним (хотя некоторые из них - только для последних версий Windows). Большинство из них определено для единственного виджета, например, wx.!EVT_BUTTON для кнопки и wx.EVT_MENU для выбора пункта меню. События команды описываются вместе со своими виджетами во второй части книги.

=== Работа с методами wx.EvtHandler ===
Класс wx.EvtHandler определяет множество методов, которые не вызываются при нормальных обстоятельствах. Часто используется только метод Bind(). Он создает биндеры событий, которые мы обсуждали. Метод принимает следующие параметры:
{{{#!highlight python
Bind(event, handler, source=None, id=wx.ID_ANY, id2=wx.ID_ANY)
}}}

Функция Bind() связывает событие, объект и обработчик. Параметр event обязательный. Это объект класса wx.PyEventBinder как описано в разделе 3.3. Параметр handler, также обязательный. Это объект, поддерживающий вызов, обычно это метод или функция с единственным параметром – объектом событием. Параметром обработчика может быть None, если событие не связано с обработчиком. Параметр source – это виджет, который является источником события. Параметр используется, когда виджет, вызывающий событие не тот, который используется как обработчик. Как правило, обработчики событий - это методы вашего класса wx.Frame. С этими методами вы связываете события от виджетов, содержащихся в окне. Однако, если родительское окно содержит больше чем один источник события нажатия кнопки (например в окне есть две кнопки OK и Cancel), параметр source используется, чтобы различить какой объект является источником события. Следующий пример демонстрирует это:
{{{#!highlight python
self.Bind(wx.EVT_BUTTON, self.OnClick, button)
}}}
Связываются событие, объект button (и только button) и метод OnClick(). В листинге 3.1 дан пример использования метода Bind() с параметром source и без него. Вы не обязаны называть ваши обработчики событий On<event>, но это - общее соглашение.

'''Листинг 3.1 Пример использования метода Bind() с параметром source и без него'''
{{{#!highlight python
def __init__(self, parent, id):
    wx.Frame.__init__(self, parent, id, 'Frame With Button',
        size=(300, 100))
    panel = wx.Panel(self, -1)
    button = wx.Button(panel, -1, "Close", pos=(130, 15),
        size=(40, 40))
    # (1) Binding the frame close event
    self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
    # (2) Binding the button event
    self.Bind(wx.EVT_BUTTON, self.OnCloseMe, button)

def OnCloseMe(self, event):
    self.Close(True)

def OnCloseWindow(self, event):
    self.Destroy()
}}}
'''(1)''' В этой строке событие закрытия фрейма связывается с методом self.OnCloseWindow. Так как событие и вызвано и связано с фреймом, нет необходимости передавать параметр source.

'''(2)''' Эта строка связывает событие нажатия кнопки с кнопкой и методом self.OnCloseMe. В этом случае, кнопка, генерирующая событие, это не фрейм. Поэтому, кнопку нужно передать как параметр методу Bind, чтобы wxPython мог различать события нажатия этой кнопки и события нажатия других кнопок фрейма.

Вы можете также использовать параметр source, чтобы идентифицировать элемент, даже если элемент не является источником события. Например, вы можете связать события меню с обработчиками даже при том, что события меню технически вызваны фреймом. Листинг 3.2 иллюстрирует пример связывания событий меню.

'''Листинг 3.2 Связывание событий меню'''
{{{#!highlight python
#!/usr/bin/env python

import wx

class MenuEventFrame(wx.Frame):

    def __init__(self, parent, id):
        wx.Frame.__init__(self, parent, id, 'Menus',
                size=(300, 200))
        menuBar = wx.MenuBar()
        menu1 = wx.Menu()
        menuItem = menu1.Append(-1, "&Exit...")
        menuBar.Append(menu1, "&File")
        self.SetMenuBar(menuBar)
        self.Bind(wx.EVT_MENU, self.OnCloseMe, menuItem)

    def OnCloseMe(self, event):
        self.Close(True)

if __name__ == '__main__':
    app = wx.PySimpleApp()
    frame = MenuEventFrame(parent=None, id=-1)
    frame.Show()
    app.MainLoop()
}}}
Параметры id и id2 метода Bind() определяют источник события, используя число ID, а не виджет непосредственно. Как правило, id и id2 не требуются, так как идентификатор (ID) источника события может быть извлечен из параметра source. Однако, иногда использование ID непосредственно имеет смысл. Например, если вы используете предопределенные ID для диалогового окна, легче использовать число ID, чем использовать виджет. Если вы используете оба параметра (и id и id2), то вы можете связать с событием несколько виджетов, идентификаторы которых находятся в диапазоне от id до id2. Это полезно, когда идентификаторы виджетов последовательны.
Благодаря использованию типов событий, wxPython может очень точно управлять событиями, все еще позволяя подобным событиям быть объектами того же самого класса, и совместно использовать данные и функциональные возможности. Это делает написание обработчиков событий намного более чистыми в wxPython, чем в других инструментариях для создания интерфейса.

Биндеры позволяют связать виджет, событие и функцию обработчик. Эта связь позволяет системе wxPython отвечать на события виджета, выполняя код функции обработчика. В wxPython, любой объект, который может ответить на событие, является подклассом wx.EvtHandler. Все отображаемые объекты – это подклассы wx.EvtHandler, следовательно каждый виджет в приложении wxPython может отвечать на события. Класс wx.EvtHandler может использоваться не только с виджетами, например его использует wx.App. Таким образом объекты, отвечающие на события, не ограничены виджетами. Фраза: виджет может ответить на события, означает, что виджет может создать биндер, который wxPython использует для диспетчеризации событий. Программный код функции обработчика не обязан располагаться в классе wx.EvtHandler.

==== Старый стиль связывания ====

Метод Bind() появился в wxPython начиная с версии 2.5. В предыдущих версиях wxPython, имена EVT_* использовались как функции, и связывание выглядело следующим образом:
{{{#!highlight python
wx.EVT_BUTTON(self, self.button.GetId(), self.OnClick)
}}}

Недостаток старого стиля в том, что он не выглядит и не действует как объектно-ориентированный метод. Однако, старый стиль все еще работает в версии 2.5 (потому что объекты wx.EVT * поддерживают вызов), и вы, возможно, будете встречать его в коде wxPython.

В таблице 3.3 представлен список некоторых методов класса wx.EvtHandler, которые вы можете использовать для управления процессом обработки событий.

'''Таблица 3.3 Обычно используемые методы класса wx.EvtHandler'''

||'''Метод'''||'''Описание'''||
||AddPendingEvent(event)||Помещает параметр event в систему обработки событий. Подобен методу ProcessEvent(), но, в отличие от него, не вызывает непосредственную обработку события. Вместо этого событие добавляется в очередь событий.||
||Bind(event, handler, source=None,
id=wx.ID_ANY, id2=wx.ID_ANY)||См. полное описание в разделе 3.3.1.||
||GetEvtHandlerEnabled() SetEvtHandlerEnabled( boolean)||Свойство имеет значение True, если обработчик в настоящее время обрабатывает события, иначе - False.||
||ProcessEvent(event)||Помещает объект event в систему обработки событий для непосредственной обработки.||

Работа в среде, управляемой событиями

Эта глава включает:

  • Программирование в среде, управляемой событиями
  • Связь событий с обработчиками
  • Распространение событий в wxPython
  • Создание своих событий

Обработка событий - фундаментальный механизм, на котором основана работа программ wxPython. Такие программы называют программами, управляемыми событиями. В этой главе, мы обсудим, чем управляемое событиями приложение отличается от традиционного. Мы дадим краткий обзор понятий и терминологии, используемой в программирование GUI. Мы также расскажем о жизненном цикле типичной управляемой событиями программы.

Событие – это то, что случается в вашей системе, и на что ваше приложение может отреагировать, вызывая определенную функцию. Событие может быть низкоуровневым действием пользователя, типа перемещения мыши или нажатия клавиши, или высокоуровневым, типа выбора из меню. Событие может также быть создано операционной системой. Созданные вами объекты также могут создавать собственные события. Приложение wxPython работает, связывая определенный вид события с определенным программным кодом, который должен быть выполнен в ответ на событие. Такой программный код, связанный с событием, называется обработчиком события.

Эта глава рассказывает о событиях, о том как писать код для обработки событий, и о том как система wxPython вызывает ваш код, когда событие произошло. Мы также покажем вам, как добавить собственные события к библиотеке wxPython, которая содержит список стандартных пользовательских и системных действий.

Терминология для понимания событий

Эта глава содержит много терминов, большая часть которых начинается со слова событие (event). Таблица 3.1 - справочник терминов, которые мы будем использовать.

Таблица 3.1 Термины, связанные с событием

Термин

Описание

event

Событие. Что-то, что случается во время работы вашего приложения, и что требует какой-то реакции.

event object

Событие как объект. События представлены как объекты класса wx.!Event и его подклассов, типа wx.CommandEvent и wx.MouseEvent.

event type

Тип события. В wxPython каждое событие имеет целочисленный идентификатор – тип события, который уточняет природу события. Например, у события wx.MouseEvent есть тип, который указывает, что событие является или щелчком мыши или перемещением мыши.

event source

Источник события. Любой объект wxPython, который создал событие. Например: кнопка, пункт меню, список или любой другой виджет.

event-driven

Программа имеющая такую структуру, где большая часть времени отводится на ожидание и обработку событий.

event queue

Очередь событий. Список событий, которые уже произошли, но еще не были обработаны.

event handler

Обработчик события. Функция или метод, который вызывается в ответ на событие.

event binder

Биндер. Объект wxPython, который инкапсулирует связь между определенным виджетом, определенным типом события и соответствующим обработчиком. Чтобы быть вызванными, все обработчики событий должны быть зарегистрированы биндерами.

wx.EvtHandler

Класс wxPython, который позволяет его объектам создавать связь между биндером определенного типа, источником события (event source) и обработчиком события (event handler). Отметьте, что класс wx.EvtHandler не то же самое, что функция или метод обработчик события.

Мы надеемся, что эта таблица не позволит вам перепутать обработчики событий с биндерами. Обращайтесь к этой таблице по мере необходимости. Мы начнем с краткого обзора управляемого событиями программирования, затем мы обсудим специфические особенности того, как все это реализовано в wxPython.

Программирование управляемое событиями

Программа, управляемая событиями, имеет структуру управления, которая, главным образом, получает события и отвечает на них. Структура программы wxPython (или любой другой программы, управляемой событиями) существенно отличается от структуры обычного сценария Python. Типичный сценарий Python имеет определенную отправную точку и определенный пункт окончания, и программист управляет порядком выполнения, используя условные операторы, циклы и функции. Программа не линейна, но ее порядок часто независим от пользовательских действий.

С точки зрения пользователя, программа wxPython большую часть времени ничего не делает. Она ожидает пока пользователь или система проявят свою активность. Структура программы wxPython – это пример архитектуры программы, управляемой событиями. На рисунке 3.1 показаны главные части программы, управляемой событиями.

Рисунок 3.1 Схематичное изображение цикла обработки событий. Показан жизненный путь программы, пользовательские события и вызов обработчиков.

Цикл обработки событий можно сравнить с оператором в сервис-центре. Пока нет входящих звонков оператор ожидает. Наконец происходит событие - телефонный звонок. В процессе общения с клиентом, оператор должен получить достаточно информации, чтобы знать к кому переадресовать клиента для ответа. После пересылки, оператор ждет следующего звонка.

Хотя каждая система управляемая событиями имеет свои особенности, между ними много общего. Первичные характеристики программы управляемой событиями следующие:

  • После начальной установки, большую часть времени программа проводит в цикле, ожидая события. Вход в этот цикл показывает начало пользовательской интерактивной части программы, и выход из цикла показывает ее конец. В wxPython, этот цикл – метод wx.!App.MainLoop(). Он должен быть явно вызван в вашем сценарии. Выход из цикла происходит, когда все окна верхнего уровня закрыты.

  • Программа реагирует на события, которые могут произойти в среде программы. Обычно, события вызываются пользовательской деятельностью, но могут также быть результатом деятельности системы, или произвольного кода в другом месте программы. В wxPython, все события – объекты класса wx.Event или производного от него. Каждое событие имеет атрибут тип события (event type) (см. таблицу 3.1), который позволяет различать виды событий.
  • В цикле, программа периодически проверяет, случилось ли что-нибудь требующее ответа. Есть несколько механизмов, которыми система, управляемая событиями, может получать информацию о событиях. Наиболее популярный метод, используемый wxPython: события помещаются в общую очередь по мере поступления, а затем извлекаются из нее и обрабатываются.
  • Когда событие происходит, система его обрабатывает, вызывая программный код, связанный с этим событием. В wxPython, родные системные события переведены в объекты wx.Event и созданы методы wx.EvtHandler.ProcessEvent() для того, чтобы послать события надлежащему обработчику. На рисунке 3.3 схематически изображен этот процесс. Составляющие части механизма обработки событий – биндеры (event binder) и обработчики событий. Биндер (event binder) - предопределенный объект wxPython. Есть отдельный биндер для каждого типа события. Обработчик (event handler) - функция или метод, который принимает объект события как параметр. Обработчик вызывается, когда пользователь вызывает соответствующее событие.

Далее, мы подробно обсудим как это реализовано в wxPython. И начнем с обработчиков событий.

Программирование обработчиков событий

В вашем коде wxPython, события и обработчики событий должны быть связаны с соответствующими виджетами. Например, событие нажатия кнопки будет послано определенному обработчику, связанному с этой кнопкой. Для связи события, виджета и обработчика используете специальный объект - биндер. Например,

   1 self.Bind(wx.EVT_BUTTON, self.OnClick, aButton)

используется предопределенный объект биндер wx.EVT_BUTTON для связи события нажатия кнопки aButton с методом self.OnClick. Метод Bind() – это метод класса wx.EvtHandler, который является базовым классом всех отображаемых объектов. Поэтому, этот пример кода может быть применен к любому виджету.

Вам кажется, что программа wxPython пассивно ждет событие, но на самом деле она выполняет метод wx.App.MainLoop(). MainLoop() может быть переведен в упрощенный псевдокод Python:

   1 while True:
   2     while not self.Pending():
   3         self.ProcessIdle()
   4     self.DoMessage()

Другими словами, пока нет событий, система простаивает. При появлении события, посылается сообщение соответствующему обработчику.

Проектирование программ управляемых событиями

Природа управляемой событиями программы wxPython предполагает определенные способы проектирования и кодирования. Так как неизвестно, когда произойдет событие, программист уступает большую часть управления программой пользователю. Большая часть кода в вашей программе wxPython выполняется как прямой или косвенный результат действий пользователя или системы. Например, сохранение документа в вашей программе происходит после того, как пользователь выберет пункт меню, нажмет кнопку панели инструментов или нажмет горячую клавишу. Любое из этих событий может вызвать обработчик, который сохраняет документ пользователя.

Архитектура программ, управляемых событиями, является распределенной. Код, который вызывается в ответ на событие, обычно не определяется виджетом, который вызвал это событие. Например, программный код, вызванный в ответ на нажатие кнопки, не обязан быть частью определения кнопки. Он может быть определен во фрейме или любом другом месте. Объединение такой архитектуры с объектно-ориентированным дизайном позволяет создавать программный код многократного использования. Вы найдете, что гибкая природа Python делает особенно простым повторное использование общих обработчиков событий в различных приложениях wxPython. С другой стороны, распределенная природа программы, управляемой событиями, затрудняет ее понимание и поддержку. Иногда бывает трудно разыскать метод, вызываемый в ответ на событие. (В некоторой степени, эта проблема верна для всего объектно-ориентированного программирования). В главе 5 мы дадим рекомендации, позволяющие упорядочить код программ, управляемых событиями.

Генерация событий

В wxPython, большинство виджетов генерирует высокоуровневые события в ответ на события более низкого уровня. Например, щелчок мыши на кнопке wx.Button генерирует событие wx.CommandEvent типа EVT_BUTTON. Точно так же при перетаскивании мышью угла окна, wxPython автоматически создаст событие wx.SizeEvent. Преимущество высокоуровневых событий состоит в том, что они позволяют сосредоточиться на самих событиях, вместо того, чтобы отслеживать каждый щелчок мыши. Высокоуровневые события могут также содержать полезную информацию о событии. Поскольку вы создаете ваши собственные виджеты, вы можете определить ваши собственные события.

В wxPython cобытия – это объекты класса wx.Event или производного от него. Базовый класс wx.Event – это небольшой абстрактный класс, содержащий методы чтения и записи для свойств, определенных для всех событий, типа EventType, EventObject, и !Timestamp. Различные подклассы wx.Event добавляют дополнительную информацию. Например, wx.MouseEvent содержит информацию о координатах курсора миши и нажатой кнопке.

В wxPython определено несколько различных подклассов wx.Event. Таблица 3.2 содержит список некоторых из классов событий, с которыми вы скорее всего столкнетесь. Помните, один класс события может иметь много типов. Каждый тип события соответствует различным действиям пользователя.

Таблица 3.2 Важнейшие подклассы wx.Event

Событие

Описание

wx.CloseEvent

Происходит при закрытии фрейма. Тип события позволяет различить нормальное закрытие фрейма и системное завершение.

wx.CommandEvent

Происходит при взаимодействии пользователя с различными виджетами, типа щелчка кнопки, выбора пункта меню или радио- кнопки. Каждое из этих отдельных действий имеет собственный тип. Многие более сложные виджеты, типа списка или сетки (grid), определяют подклассы wx.CommandEvent. Обработка команд отличается от обработки других событий.

wx.KeyEvent

Происходит при нажатии клавиши на клавиатуре. Типы: key down, key up и key press.

wx.MouseEvent

События мыши. Типы события различают перемещение мыши и щелчок мыши. Есть отдельные типы, в зависимости от нажатой кнопки и для одиночного и двойного щелчка.

wx.PaintEvent

Происходит, когда содержимое окна должно быть перерисовано.

wx.SizeEvent

Происходит при изменении размеров окна. Обычно это приводит к изменению размеров или расположения элементов окна.

wx.TimerEvent

Может быть создано классом wx.Timer, который генерирует периодические события.

Как правило, объекты событий сами ничего не делают. Событие передается как параметр соответствующему обработчику, используя биндер и систему обработки событий.

Как связать событие с обработчиком?

Биндеры состоят из объектов класса wx.PyEventBinder. Объекты wx.PyEventBinder определены для всех типов поддерживаемых событий. Вы можете создать ваши собственные биндеры для ваших собственных типов событий, когда это необходимо. Для каждого типа события определен свой биндер. Типы событий более детализированы чем подклассы wx.Event. Например, класс wx.MouseEvent имеет четырнадцать отдельных типов событий.

В wxPython, имена объектов биндеров глобальны. Чтобы ясно связать типы объектов с обработчиками, эти имена начинаются с wx.EVT_ и соответствуют названиям макроопределений, используемых в коде C++ wxWidgets. В коде wxPython, имя биндера используются вместо типа события. В результате, и это стоит подчеркнуть, имя биндера – это не целочисленный код, который вы получили бы, вызывая метод GetEventType() объекта wx.Event. Челочисленные коды типов событий имеют полностью различный набор глобальных названий, и не часто используются практически.

Для примера рассмотрим типы событий wx.MouseEvent. Как мы упоминали, их – четырнадцать. Девять из них описывают нажатия кнопок мыши. Вот их имена:

   1 wx.EVT_LEFT_DOWN
   2 wx.EVT_LEFT_UP
   3 wx.EVT_LEFT_DCLICK
   4 wx.EVT_MIDDLE_DOWN
   5 wx.EVT_MIDDLE_UP
   6 wx.EVT_MIDDLE_DCLICK
   7 wx.EVT_RIGHT_DOWN
   8 wx.EVT_RIGHT_UP
   9 wx.EVT_RIGHT_DCLICK

Дополнительно, событие типа wx.!EVT_MOTION происходит при перемещении мыши. Собития типов wx.!ENTER_WINDOW и wx.!LEAVE_WINDOW возникают, когда курсор мыши входит в область виджета и выходит из нее. Событие типа wx.!EVT_MOUSEWHEEL происходит из-за движения колесика мыши. Наконец, вы можете связать все события мыши с единственной функцией, используя тип wx.!EVT_MOUSE_EVENTS.

Аналогично, класс wx.CommandEvent имеет 28 различных типов событий, связанных с ним (хотя некоторые из них - только для последних версий Windows). Большинство из них определено для единственного виджета, например, wx.!EVT_BUTTON для кнопки и wx.EVT_MENU для выбора пункта меню. События команды описываются вместе со своими виджетами во второй части книги.

Работа с методами wx.EvtHandler

Класс wx.EvtHandler определяет множество методов, которые не вызываются при нормальных обстоятельствах. Часто используется только метод Bind(). Он создает биндеры событий, которые мы обсуждали. Метод принимает следующие параметры:

   1 Bind(event, handler, source=None, id=wx.ID_ANY, id2=wx.ID_ANY)

Функция Bind() связывает событие, объект и обработчик. Параметр event обязательный. Это объект класса wx.PyEventBinder как описано в разделе 3.3. Параметр handler, также обязательный. Это объект, поддерживающий вызов, обычно это метод или функция с единственным параметром – объектом событием. Параметром обработчика может быть None, если событие не связано с обработчиком. Параметр source – это виджет, который является источником события. Параметр используется, когда виджет, вызывающий событие не тот, который используется как обработчик. Как правило, обработчики событий - это методы вашего класса wx.Frame. С этими методами вы связываете события от виджетов, содержащихся в окне. Однако, если родительское окно содержит больше чем один источник события нажатия кнопки (например в окне есть две кнопки OK и Cancel), параметр source используется, чтобы различить какой объект является источником события. Следующий пример демонстрирует это:

   1 self.Bind(wx.EVT_BUTTON, self.OnClick, button)

Связываются событие, объект button (и только button) и метод OnClick(). В листинге 3.1 дан пример использования метода Bind() с параметром source и без него. Вы не обязаны называть ваши обработчики событий On<event>, но это - общее соглашение.

Листинг 3.1 Пример использования метода Bind() с параметром source и без него

   1 def __init__(self, parent, id):
   2     wx.Frame.__init__(self, parent, id, 'Frame With Button',
   3         size=(300, 100))
   4     panel = wx.Panel(self, -1)
   5     button = wx.Button(panel, -1, "Close", pos=(130, 15),
   6         size=(40, 40))
   7     # (1) Binding the frame close event
   8     self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
   9     # (2) Binding the button event
  10     self.Bind(wx.EVT_BUTTON, self.OnCloseMe, button)
  11 
  12 def OnCloseMe(self, event):
  13     self.Close(True)
  14 
  15 def OnCloseWindow(self, event):
  16     self.Destroy()

(1) В этой строке событие закрытия фрейма связывается с методом self.OnCloseWindow. Так как событие и вызвано и связано с фреймом, нет необходимости передавать параметр source.

(2) Эта строка связывает событие нажатия кнопки с кнопкой и методом self.OnCloseMe. В этом случае, кнопка, генерирующая событие, это не фрейм. Поэтому, кнопку нужно передать как параметр методу Bind, чтобы wxPython мог различать события нажатия этой кнопки и события нажатия других кнопок фрейма.

Вы можете также использовать параметр source, чтобы идентифицировать элемент, даже если элемент не является источником события. Например, вы можете связать события меню с обработчиками даже при том, что события меню технически вызваны фреймом. Листинг 3.2 иллюстрирует пример связывания событий меню.

Листинг 3.2 Связывание событий меню

   1 #!/usr/bin/env python
   2 
   3 import wx
   4 
   5 class MenuEventFrame(wx.Frame):
   6 
   7     def __init__(self, parent, id):
   8         wx.Frame.__init__(self, parent, id, 'Menus',
   9                 size=(300, 200))
  10         menuBar = wx.MenuBar()
  11         menu1 = wx.Menu()
  12         menuItem = menu1.Append(-1, "&Exit...")
  13         menuBar.Append(menu1, "&File")
  14         self.SetMenuBar(menuBar)
  15         self.Bind(wx.EVT_MENU, self.OnCloseMe, menuItem)
  16 
  17     def OnCloseMe(self, event):
  18         self.Close(True)
  19 
  20 if __name__ == '__main__':
  21     app = wx.PySimpleApp()
  22     frame = MenuEventFrame(parent=None, id=-1)
  23     frame.Show()
  24     app.MainLoop()

Параметры id и id2 метода Bind() определяют источник события, используя число ID, а не виджет непосредственно. Как правило, id и id2 не требуются, так как идентификатор (ID) источника события может быть извлечен из параметра source. Однако, иногда использование ID непосредственно имеет смысл. Например, если вы используете предопределенные ID для диалогового окна, легче использовать число ID, чем использовать виджет. Если вы используете оба параметра (и id и id2), то вы можете связать с событием несколько виджетов, идентификаторы которых находятся в диапазоне от id до id2. Это полезно, когда идентификаторы виджетов последовательны. Благодаря использованию типов событий, wxPython может очень точно управлять событиями, все еще позволяя подобным событиям быть объектами того же самого класса, и совместно использовать данные и функциональные возможности. Это делает написание обработчиков событий намного более чистыми в wxPython, чем в других инструментариях для создания интерфейса.

Биндеры позволяют связать виджет, событие и функцию обработчик. Эта связь позволяет системе wxPython отвечать на события виджета, выполняя код функции обработчика. В wxPython, любой объект, который может ответить на событие, является подклассом wx.EvtHandler. Все отображаемые объекты – это подклассы wx.EvtHandler, следовательно каждый виджет в приложении wxPython может отвечать на события. Класс wx.EvtHandler может использоваться не только с виджетами, например его использует wx.App. Таким образом объекты, отвечающие на события, не ограничены виджетами. Фраза: виджет может ответить на события, означает, что виджет может создать биндер, который wxPython использует для диспетчеризации событий. Программный код функции обработчика не обязан располагаться в классе wx.EvtHandler.

Старый стиль связывания

Метод Bind() появился в wxPython начиная с версии 2.5. В предыдущих версиях wxPython, имена EVT_* использовались как функции, и связывание выглядело следующим образом:

   1 wx.EVT_BUTTON(self, self.button.GetId(), self.OnClick)

Недостаток старого стиля в том, что он не выглядит и не действует как объектно-ориентированный метод. Однако, старый стиль все еще работает в версии 2.5 (потому что объекты wx.EVT * поддерживают вызов), и вы, возможно, будете встречать его в коде wxPython.

В таблице 3.3 представлен список некоторых методов класса wx.EvtHandler, которые вы можете использовать для управления процессом обработки событий.

Таблица 3.3 Обычно используемые методы класса wx.EvtHandler

Метод

Описание

AddPendingEvent(event)

Помещает параметр event в систему обработки событий. Подобен методу ProcessEvent(), но, в отличие от него, не вызывает непосредственную обработку события. Вместо этого событие добавляется в очередь событий.

||Bind(event, handler, source=None, id=wx.ID_ANY, id2=wx.ID_ANY)||См. полное описание в разделе 3.3.1.||

GetEvtHandlerEnabled() SetEvtHandlerEnabled( boolean)

Свойство имеет значение True, если обработчик в настоящее время обрабатывает события, иначе - False.

ProcessEvent(event)

Помещает объект event в систему обработки событий для непосредственной обработки.

Перевод: Володеев Сергей

WxPython_in_Action/Работа_в_среде_управляемой_событиями (последним исправлял пользователь alafin 2010-05-19 08:08:27)