Python大佬手把手教你用wxPython模块编写界面程序( 三 )


事件可以有多重产生方式,大部分是用户触发的,也有可能由其他方式产生,比如网络连接、窗口管理和计时器调用等 。
关于事件,这里面有几个过程和要素:
事件循环Event Loop(比如wxPython的MainLoop()方法),它一直在寻找和捕获事件Event(比如wx.EVT_SIZE、wx.EVT_CLOSE等);当捕获到事件后,就通过分发器dispatcher将事件分发到事件句柄Event Handler(事件句柄是对事件进行响应的动作方法);事件本身与事件句柄的映射由Event Binder来完成(即Bind()方法) 。
对用户编程来说,最常打交道的就是Bind()方法:
Bind(event, handler, source=None, id=wx.ID_ANY, id2=wx.ID_ANY)溯源起来,该Bind()方法是定义在EvtHandler类中,而EvtHandler又派生了Window类,Window类又是绝大多数组件的父类,因此可以在组件中直接使用该方法(如果想将事件解绑,则可以调用Unbind()方法,其参数跟下面的参数相同) 。
event参数就是事件对象,它指定了事件类型;
handler就是对该事件的响应方法,这个通常要由编程自定义完成;
source是指该事件来自于哪个组件,比如很多组件都能产生同样的事件,就需要指定具体的来源,比如很多button都能产生鼠标点击事件 。这里面就有一个很tricky的地方,假设self是一个panel,该panel上有很多buttons,名为bt1、bt2,那么self.Bind(event, handler, source=self.bt1)和self.bt1.Bind(event, handler)有什么区别呢?两者看起来的效果是相同的,这里有一个帖子详细说明了两者的区别 ;
id是通过ID来指定事件来源,而上面的source是通过直接指定实例,两者目的相同;关于组件的ID,主要有两种创建方式:
(1)让系统自动创建:即使用-1或wx.ID_ANY,系统自动创建的ID都是负数,因此用户自己创建的ID都应该是正数,此种情况通常用于不用改变状态的组件 。可以使用GetId()来获取该隐形id;
(2)标准ID:wxPython提供了一些标准IDs,比如wx.ID_SAVE、wx.ID_NEW等;
id2是指定多个IDs,上面的id是一次只能指定单个ID 。
这里面有个很好玩的用法,如果想批量给多个同类组件绑定事件,可以用lambda函数,比如:
#!/usr/bin/python# -*- coding: UTF-8 -*-__author__ = 'huangbinghe@gmail.com'import wxclass TestFrm(wx.Frame):"""TestFrm"""def __init__(self, *arg, **kw):super().__init__(*arg, **kw)panel = wx.Panel(self, -1)box = wx.BoxSizer(wx.VERTICAL)for i in range(5):btn = wx.Button(panel, -1, label="test-{}".format(i))btn.Bind(wx.EVT_BUTTON, lambda e, mark=i: self.on_click(e, mark))box.Add(btn, 0, wx.LEFT)panel.SetSizer(box)def on_click(self, event, mark):wx.MessageDialog(self, 'click mark:{}'.format(mark), 'click btn', wx.ICON_INFORMATION).ShowModal() if __name__ == '__main__':app = wx.App()frm = TestFrm(None, title="hello world")frm.Show()app.MainLoop()事件传播有两种类型的事件:basic events和command events 。它们两者的区别在于是否传播上 。事件的传播是指事件从触发该事件的子组件开始,传递给其父组件,并观察其响应 。Basic events不传播,而command events传播 。比如wx.CloseEvent就是一个basic event,它不传播,因为如果传播给父组件就很没有道理 。
默认情形下,在事件句柄中的事件是阻止传播的,如果想让它继续传播,需要调用skip()方法(这个也解释了上面的self.Bind(event, handler, source=self.bt1)和self.bt1.Bind(event, handler)的区别) 。
常见事件窗口移动事件:wx.EVT_MOVE
窗口销毁事件:wx.EVT_CLOSE,发生在点击工具栏的关闭按钮、Alt+F4或从开始菜单关闭计算机时(注意销毁窗口是destroy()方法)
按钮事件:wx.EVT_BUTTON,点击一个按钮时
菜单事件:wx.EVT_MENU,点击一个菜单时
绘图事件:wx.EVT_PAINT,改变窗口尺寸或最大化窗口时(最小化窗口时不会产生该事件)
焦点事件:wx.EVT_SET_FOCUS,当某组件成为焦点时;wx.EVT_KILL_FOCUS,当某组件失去焦点时
键盘事件:wx.EVT_KEY_DOWN,键盘按下;wx.EVT_KEY_UP,键盘弹起;wx.EVT_CHAR,这个应该是为了兼容非英语字符 。
对话框对话框是一种非常重要的人机交互的手段,可以使得用户输入数据、修改数据、更改程序配置等 。
预定义的消息对话框消息对话框是为了向用户展示消息,可以通过一些预定义的旗标来定制消息对话框的按钮和图标,如下图所示:

Python大佬手把手教你用wxPython模块编写界面程序

文章插图
 
?
自定义对话框若想自定义对话框,只需继承wx.Dialog即可 。
常用组件基础组件wxPython提供了大量基础组件,如:


推荐阅读