关于 wxPython 中创建自定义事件步骤的理解,有一点疑问

关于 wxPython 中创建自定义事件步骤的理解,有一点疑问

《wxPython in action》中提到创建自定义事件的步骤如下:

1、定义一个新的事件类,它是wxPython的wx.PyEvent类的子类。如果你想这个事件被作为命令事件,你可以创建wx.PyCommandEvent的子类。像许多wxPython中的覆盖一样,一个类的py版本使得wxWidget系统明白用Python写的覆盖C++方法的方法。

2、创建一个事件类型和一个绑定器对象去绑定该事件到特定的对象。

3、添加能够建造这个新事件实例的代码,并且使用ProcessEvent()方法将这个实例引入事件处理系统。一旦该事件被创建,你就可以像使用其它的wxPython事件一样创建绑定和处理器方法。

[Copy to clipboard] [ - ]
CODE:
import wx


class TwoButtonEvent(wx.PyCommandEvent):   #1 定义事件         
    def __init__(self, evtType, id):
        wx.PyCommandEvent.__init__(self, evtType, id)
        self.clickCount = 0

    def GetClickCount(self):
        return self.clickCount

    def SetClickCount(self, count):
        self.clickCount = count

myEVT_TWO_BUTTON = wx.NewEventType() #2 创建一个事件类型   
EVT_TWO_BUTTON = wx.PyEventBinder(myEVT_TWO_BUTTON, 1)  #3 创建一个绑定器对象

class TwoButtonPanel(wx.Panel):
    def __init__(self, parent, id=-1, leftText="Left",
            rightText="Right"):
        wx.Panel.__init__(self, parent, id)
        self.leftButton = wx.Button(self, label=leftText)
        self.rightButton = wx.Button(self, label=rightText,
                                     pos=(100,0))
        self.leftClick = False
        self.rightClick = False
        self.clickCount = 0
#4 下面两行绑定更低级的事件
        self.leftButton.Bind(wx.EVT_LEFT_DOWN, self.OnLeftClick)
        self.rightButton.Bind(wx.EVT_LEFT_DOWN, self.OnRightClick)

    def OnLeftClick(self, event):
        self.leftClick = True
        self.OnClick()
        event.Skip()   #5 继续处理


    def OnRightClick(self, event):
        self.rightClick = True
        self.OnClick()
        event.Skip()   #6 继续处理


    def OnClick(self):
        self.clickCount += 1
        if self.leftClick and self.rightClick:
            self.leftClick = False
            self.rightClick = False
            evt = TwoButtonEvent(myEVT_TWO_BUTTON, self.GetId()) #7 创建自定义事件   
            evt.SetClickCount(self.clickCount)   # 添加数据到事件
            self.GetEventHandler().ProcessEvent(evt)  #8 处理事件

class CustomEventFrame(wx.Frame):
    def __init__(self, parent, id):
        wx.Frame.__init__(self, parent, id, 'Click Count: 0',
                          size=(300, 100))
        panel = TwoButtonPanel(self)
        self.Bind(EVT_TWO_BUTTON, self.OnTwoClick, panel) #9 绑定自定义事件  

    def OnTwoClick(self, event):   #10 定义一个事件处理器函数                              
        self.SetTitle("Click Count: %s" % event.GetClickCount())


if __name__ == '__main__':
    app = wx.PySimpleApp()
    frame = CustomEventFrame(parent=None, id=-1)
    frame.Show()
    app.MainLoop()

疑问 1:
------------------------------------------------------------------------------------------------------------------------------
EVT_TWO_BUTTON = wx.PyEventBinder(myEVT_TWO_BUTTON, 1)  #3 创建一个绑定器对象
------------------------------------------------------------------------------------------------------------------------------
这句中,给 PyEventBinder 传递一个参数 1 做啥?我试了一下,不给这个参数,直接使用默认参数 0,这个程序也可以正常运行。


疑问 2:
我自己对于事件处理步骤的理解:

1. 首先创建一个事件类。
2. 由于事件类本身需要两个参数:evtType 和 id,因此还需要再创建一个 evtType 并提供 id(这里的 id 就是触发事件的 widgets 的 id?我想不是,因为并不是每个 widgets 的构造函数都有 id 这个参数。那么,这个 id 到底是什么?)
3. 提供 evtType 和 id 后,即可实例化事件类,创建一个事件实例(例如对于鼠标事件来说,创建一个“鼠标左键按下”的实例)。然后通过 bind 函数,将具体的事件实例(例如鼠标左键按下事件)与某个事件处理函数绑定到一起。

不知道这样理解对不对?

疑问 3:
------------------------------------------------------------------------------------------------------------------------------
self.Bind(EVT_TWO_BUTTON, self.OnTwoClick, panel) #9 绑定自定义事件
------------------------------------------------------------------------------------------------------------------------------
我查了一下, bind 函数的参数如下:Bind(self, event, handler, source=None, id=-1, id2=-1),这里怎么用了一个绑定器对象 (EVT_TWO_BUTTON) 作为参数啦?
对wxPython不太有研究。
首先 一般事件定义有简便方式
(myevent, myeventType) = wx.lib.newevent.NewEvent()
对于界面事件PyCommandEvent,创建其实例对象时需要指定winid

对于疑问1:PyEventBinder的第二个参数的解释在wx.PyEventBinder.__call__()中
'''For backwards compatibility with the old EVT_* functions. Should be called with either (window, func), (window, ID, func) or (window, ID1, ID2, func) parameters depending on the  type of the event.'''

0,1,2分别对应(window, func), (window, ID, func) 和 (window, ID1, ID2, func)

进而影响或者说决定bind(self, event, handler, source=None, id=wx.ID_ANY, id2=wx.ID_ANY)调用方式

对于疑问2:

对于PyCommandEvent以及子类 其构造参数id就是winid,也就是你说的触发事件的 widgets 的 id
每个widgets都有一个这样的id 创建时中没有指明,是因为默认id=-1,由python自动指派一个unique id

对于疑问3:
我的理解是 EVT_myevent = wx.PyEventBinder(myEVT_myevent, 1) 中的EVT_myevent
才是bind函数中的所需要的事件类型
这里我觉得wxpython中的事件类型是分两层的,对于PyCommandEvent(eventtype, id)中
eventtype需要wx.NewEventType()类型 以及其内部已定义的诸如wxEVT_NULL,wxEVT_FIRST,wxEVT_COMMAND_BUTTON_CLICKED此类的类型
而bind则是需要wx.PyEventBinder(myEVT_myevent, x)类型,
我也觉得有点乱,也是不太懂

感谢 yuntinghill 的回答。

非常清楚,而且专业。解决了我不少疑问,真的非常感谢。


QUOTE:
原帖由 yuntinghill 于 2008-10-5 15:04 发表
对于疑问3:
我的理解是 EVT_myevent = wx.PyEventBinder(myEVT_myevent, 1) 中的EVT_myevent
才是bind函数中的所需要的事件类型
这里我觉得wxpython中的事件类型是分两层的,对于PyCommandEvent(eventtyp ...

研究出来啦,实际上 默认的那些

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

之类的,也是 PyEventBinder 的实例。嘿嘿。