基于事件驱动(event-driven)的这种消息响应机制我们应该很熟悉了。有关这个的就不说了,直接看看在wxpython中这个事件驱动是怎么实现的。
先看一下下面几个概念:
1. event :Something
that happens during your application that requires a response.
2.event object:The
concrete representation of an event in wxPython including data
attributes that encapsulate the specifics of the event. Events are
represented as instances of the wx.Event class and its subclasses,
such as wx.CommandEvent and wx.MouseEvent.
3.event type: An
integer ID that wxPython adds to every event object. The event type
gives further information about the nature of the event. For
example, the event type of a wx.MouseEvent indicates whether the
event is a mouse click or a mouse move.
4.event source :Any
wxPython object that creates events. Examples are buttons, menu
items, list boxes, or any other widget.
5.event-driven :A
program structure where the bulk of time is spent waiting for, or
respondingto, events.
6.event queue: A
continuously maintained list of events that have already occurred,
but have not yetbeen processed.
7.event handler: A
written function or method that is called in response to an event.
Also called a handler function or handler method.
8.event binder :A
wxPython object that encapsulates the relationship between a
specific widget, a specific event type, and an event handler. In
order to be invoked, all event handlers
must be registered with an event binder.
9.wx.EvtHandler :A
wxPython class that allows its instances to create a binding
between an event binder of a specific type, an event source, and an
event handler. Note that the class wx.EvtHandler is not the same
thing as an event handler function or method
defined previously.
首先是如何实现消息的绑定:
self.Bind(wx.EVT_BUTTON,
self.OnClick, aButton)
这句话就是把名为aButton的一个按钮的点击事件(wx._EVT_BUTTON)和一个函数self.OnClick()绑定了,只要我们在程序运行后点击这个按钮,程序就会去执行OnClick()函数。Self.Bind,产生的一个是Event
binder,是它把一个组件和事件已经这个事件对象的响应结合了起来。
下面几个简单例子:
第一个是对按钮点击的响应:
import wx
class InsertFrame(wx.Frame):
def
__init__(self,parent,id):
wx.Frame.__init__(self,parent,id,'Frame with
Button',size=(300,100))
panel=wx.Panel(self)
button=wx.Button(panel,label="Close",pos=(125,10),size=(50,50))
self.Bind(wx.EVT_BUTTON,self.OnCloseMe,button)
self.Bind(wx.EVT_CLOSE,self.OnCloseWindow)
def
OnCloseMe(self,event):
self.Close(True)
def
OnCloseWindow(self,event):
self.Destroy()
if __name__=='__main__':
app=wx.PySimpleApp()
frame=InsertFrame(parent=None,id=-1)
frame.Show()
app.MainLoop()
第二个是对菜单点击的响应:
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()
有了event以及event handler,只要这个event被触发了,那么与之对应的handler就会进行处理。
在wxpython中有一个wx.Event类,是一个事件类,他有很多子类,比如wx.CloseEvent,wx.CommandEvent,wx.KeyEvent,wx.MouseEvent
wx.PaintEvent wx.SizeEvent
wx.TimerEvent代表了不同的事件类型。这个每个子类里有包含了不同的很多event
type,比如我们上面的wx.EVT_BUTTON和wx.EVT_MENU就是wx.CommandEvent里面的。在wx.MouseEvent里,关于鼠标点击和移动的event有好多,比如,wx.EVT_LEFT_DOWN(鼠标左键按下)等等。
我们可以把这些具体的event type 和相应的event
handler和widget绑定,来完成基于event-driven的program。
关于这个时间驱动的过程,我们可以看一下下面这个图:
Step 1 Creating the event:
这个图开始,就是以event被激发开始。当我们运行一个framework的时候,用户的一些行为,比如点击按钮(当然过程可能不是这么简单,首先鼠标的移动到按钮的事件被激发,然后用户在按钮上按下右键,又松开,整个过程就会产生一个event,就是wx.EVT_BUTTON),然后对于这个button的event对象就产生了。
Step 2 Determining
whether the object is allowed to process event?
就是产生的event的widget是否允许对此event进行handle。一般默认下是可以,如果不可以的话,该event就会被过滤掉,不会对其进行反应。这个过程是由ProcessEvent()方法来完成的。
Step 3 Locating the binder
object
当确定此widget允许处理event后,ProcessEvent()会寻找这binder,就是绑定此event到当前这个object的对象,通常由Bind()方法产生。找到后,就会执行handler
fuction,这个也是由Bind()提供的。
Step 4 Determining whether to continue
processing:
当调用了第一个event
handler以后,wxpython会查看是否次Process要继续。假如在handler函数最后调用了event.Skip(),则此次handler
method完成后,系统会继续搜索符合的binding。否则此次处理结束,回到第一步之前。
Step 5 Determining whether to
propagate
就是说,如果当前object没有与此event对应的处理函数,或者这个处理函数调用了Skip(),wxpython会决定是否该传到container
hierarchy
,如果否定,则这个process会继续查一次是否有与event对应的handler,如果觉得propagate,就是向上传递该event,从当前object往他的container传,直到找到与event对应的handler处理函数。关于这个更深层的就不讨论了先。
Summary:
A wxPython application uses an event-based flow of
control. Most of the application’s time is spent in a main loop,
waiting for events and dispatching them to the appropriate handler
function.
■ All wxPython events are subclasses of the class
wx.Event. Lower level events,such as mouse clicks, are used to
build up higher order events, such as button clicks or menu item
selections. These higher order events that result from wxPython
widgets are subclasses of the class wx.CommandEvent. Most event
classes are further classified by an event type field which
differentiates between events that may all use the same data
set.
■ To capture the relationship between events and
functions, wxPython uses instances of the class wx.PyEventBinder.
There are many predefined
instances of this class, each corresponding to a
specific event type. Every wxPython widget is a subclass of
wx.EvtHandler. The wx.EvtHandler class has a method Bind(), which
is usually called at initialization with an event binder instance
and a handler function as arguments. Depending on the type of
event, other wxPython object IDs may also need to be passed to the
Bind() call.
■ Events are generally sent to the object that
generated them to search for a binding object which binds it to a
handler. If the event is a command event, the event propagates
upward through the container hierarchy until a widget is found that
has a handler for the event type. Once an event handler is found,
processing on that event stops, unless the handler calls the Skip()
method of the event. You can use the Skip() method to allow
multiple handlers to respond to a single event, or to verify that
all the default behavior for the event occurs. Certain aspects of
the main loop can be controlled using methods of wx.App.
■ Custom events can be created in wxPython, and
emitted as part of the behavior of a custom widget. Custom events
are subclasses of wx.PyEvent,custom command events are subclasses
of wx.PyCommandEvent. To create a custom event, the new class must
be defined, and a binder object must be created for each event type
managed by the new class. Finally, the event must be generated
somewhere in the system by passing a new instance to the event
handler system via the ProcessEvent() method.