天天看点

wxPython的事件处理过程详解

 wxPython的事件处理过程设计得相当合理,也做了很多简化工作(就是对于程序员更友好),但这个冰山之下,还是有很多复杂的主题,通过学习wxPython in action,终于搞明白了一些

先看两张最重要的图(还是用的我老博客livahu的两张图,没有修改图注)

wxPython的事件处理过程详解
wxPython的事件处理过程详解

现在先说说图1

wxPython应用程序使用基于事件的控制流。应用程序的大部分时间花费在一个主循环中,等待事件并分派它们到适当的处理器函数。

从用户的角度上来看,wxPython程序大部分时间什么也不做,一直闲着直到用户或系统做了些什么来触发这个事件处理函数(EventHandler)。 wxPython程序的结构就是一个事件驱动程序体系的例子。事件驱动系统的主循环类似于客户服务呼叫中心的操作者。当没有呼叫的进入的时候,这个操作者处于等待状态。当一个事件发生的时候,如电话铃响了,这个操作者开始一个响应过程,他与客户交谈直到他获得足够的信息以分派该客户给一个合适的回答者。然后操作者等待下一个事件。

再看图2

wxPython的事件类都是wx.Event类的子类,wxPython的事件分为低级事件和高级事件。鼠标敲击、移动这样的事件是低级事件,而它们可以构成高级事件,如选择一个下拉列表中的一项

由wxPython窗口部件引起的高级事件是类wx.CommandEvent的子类,默认情况,只有wx.CommandEvent及其子类的实例向上展开至容器级。其它的所有事件不这样做。

明白了这两点,就好说了,我将结合一段代码来说明问题

wxPython的事件处理过程详解

# !/usr/bin/env python 

wxPython的事件处理过程详解

# -*- coding:utf-8 -*- 

wxPython的事件处理过程详解
wxPython的事件处理过程详解

import  wx 

wxPython的事件处理过程详解
wxPython的事件处理过程详解

class  MyFrame(wx.Frame): 

wxPython的事件处理过程详解
wxPython的事件处理过程详解

     def   __init__ (self, parent, id): 

wxPython的事件处理过程详解

        wx.Frame. __init__ (self, parent, id, u ' 测试事件处理过程 ' , 

wxPython的事件处理过程详解

                size = ( 300 ,  100 )) 

wxPython的事件处理过程详解

        self.panel  =  wx.Panel(self)                              

wxPython的事件处理过程详解

        self.button  =  wx.Button(self.panel, label = u ' 鼠标离开状态 ' , pos = ( 100 ,  15 )) 

wxPython的事件处理过程详解

        self.Bind(wx.EVT_BUTTON, self.OnButtonClick, self.button)  

wxPython的事件处理过程详解

        self.button.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow, self.button)  

wxPython的事件处理过程详解

        self.button.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow, self.button)  

wxPython的事件处理过程详解
wxPython的事件处理过程详解

     def  OnButtonClick(self, event): 

wxPython的事件处理过程详解

        self.panel.SetBackgroundColour( ' Green ' ) 

wxPython的事件处理过程详解

        self.panel.Refresh() 

wxPython的事件处理过程详解
wxPython的事件处理过程详解

     def  OnEnterWindow(self, event): 

wxPython的事件处理过程详解

        self.button.SetLabel(u ' 鼠标进入状态 ' ) 

wxPython的事件处理过程详解

        event.Skip() 

wxPython的事件处理过程详解
wxPython的事件处理过程详解

     def  OnLeaveWindow(self, event): 

wxPython的事件处理过程详解

        self.button.SetLabel(u ' 鼠标离开状态 ' ) 

wxPython的事件处理过程详解

        event.Skip() 

wxPython的事件处理过程详解
wxPython的事件处理过程详解
wxPython的事件处理过程详解

if   __name__   ==   ' __main__ ' : 

wxPython的事件处理过程详解

    app  =  wx.PySimpleApp() 

wxPython的事件处理过程详解

    frame  =  MyFrame(parent = None, id =- 1 ) 

wxPython的事件处理过程详解

    frame.Show() 

wxPython的事件处理过程详解

    app.MainLoop()

wxPython的事件处理过程详解

这里,鼠标进入和离开是低级事件,所以不能向上展开至容器级,所以我是绑定到button中的,这是什么回事?

而button的点击事件,我又直接用self.Bind意味着绑定到了frame,这又是怎么回事呢?

从图2中,我们看见,当用户触发事件后,wxPython就要去处理它,首先就要创建用户所触发的事件对象,在wxPython架构中已经创建了大多数的事件类型,它们用于响应特定的用户动作或系统通知。例如,当wxPython通知“鼠标移进了一个新窗口部件对象时”,鼠标进入事件被触发,鼠标敲击事件在鼠标按下或释放后被创建。然后,这个事件对象首先被交给了创建它的对象(不要被重复的对象搞晕,在这里就是按钮对象嘛)

这是对开始检查这个对象(按钮)是不是允许去处理事件,这个通过调用wx.EvtHandler的SetEvtHandlerEnabled(boolean)方法可实现,如果boolean值为False,就没得说了,该窗口部件在事件处理中被完全绕过,与该对象关联的绑定对象也不会被搜索,并且在这步中的处理没有向下的分支。

如果为True的话,就开始寻找一个绑定器对象,如果自身没有,就看这个事件的级别了,低级还是高级,如果是低级的,那么如果找不到,你就只能调用Skip()请求进一步处理,这时只有最后一层wx.App去做处理,看有相应Bind没有,如果没有ProceeEvent就返回False,事件处理就完止

在wx.App中,我没有定义与鼠标事件的Bind,所以我只能让这个事件的绑定放到self.button上,让它自身能识别

而对于点击按钮事件,我放到哪都可以,当然要在frame范围内(包含frame)

当绑定低级事件时如鼠标按下或释放,wxPython期望捕获这些低级事件以便生成进一步的高级事件,为了进一步的高级事件处理,你必须调用Skip()方法,否则进一步的高级事件处理将被阻止

好了,写到这里,对于自定义事件,我也按作者的建议第一次看时先Skip了

继续阅读