事件是每一个GUI应用程序的组成部分。所有的GUI应用程序是事件驱动的。应用程序反应,以产生不同的事件,在其生命周期类型。事件的产生主要是由应用程序的用户。但它们可以产生,以及通过其他手段。例如互联网连接,窗口管理器,定时器。所以,当我们调用mainloop()方法,等待我们的应用程序产生事件。 mainloop()方法结束时退出应用程序。
定义
事件是一个从底层框架,通常的GUI工具包的应用程序级信息的一块。事件循环是一种编程构造和调度事件或程序中的消息等待。事件循环反复查找进程的事件。调度程序是一个过程,映射事件到事件处理程序。事件处理程序,对事件作出反应的方法。
事件对象是与事件相关联的对象。它通常是一个窗口。事件类型是一个已产生的独特的事件。事件绑定是一个对象,结合事件处理程序的事件类型。
一个简单的例子
这个例子里面讨论move事件。类型是wx.Movie的事件。此事件绑定是wx.EVT_MOTION。
''' Created on 2012-7-5 @author: Administrator ''' import wx import wx class Example(wx.Frame): def __init__(self,parent,title): super(Example,self).__init__(parent,title=title,size=(500,300)) self.InitUI() self.Centre() self.Show() def InitUI(self): wx.StaticText(self,label='x:',pos=(10,10)) wx.StaticText(self,label='y:',pos=(10,30)) self.st1 = wx.StaticText(self,label='',pos=(30,10)) self.st2 = wx.StaticText(self,label='',pos=(30,30)) self.Bind(wx.EVT_MOVE, self.OnMove) self.SetSize((250, 180)) self.SetTitle('Move event') self.Centre() self.Show(True) def OnMove(self,e): x,y = e.GetPosition() self.st1.SetLabel(str(x)) self.st2.SetLabel(str(y)) if __name__ == '__main__': app = wx.App() Example(None,title="gotoclass") app.MainLoop()
这个例子显示了当前位置的窗口,拖动窗口移动试试。
self.Bind(wx.EVT_MOVE, self.OnMove)
def OnMove(self, e): x, y = e.GetPosition() self.st1.SetLabel(str(x)) self.st2.SetLabel(str(y))
事件绑定
在wxPython中,绑定是件很容易的事情,分三个步骤:
1.定义绑定的名字:wx.EVT_SIZE, wx.EVT_CLOSE等等。
2.创建事件处理,也就是方法。
3.绑定事件与方法。
Bind(event, handler, source=None, id=wx.ID_ANY, id2=wx.ID_ANY)
2.handler就是方法。
3.source是我们要从不同的小部件中区分相同的事件类型。
4.当我们有多个按钮、菜单项等id用于区分它们。
import wx class Example(wx.Frame): def __init__(self,parent,title): super(Example,self).__init__(parent,title=title,size=(400,300)) self.InitUI() self.Centre() self.Show() def InitUI(self): self.Bind(wx.EVT_CLOSE, self.OnCloseWindow) def OnCloseWindow(self,e): dial = wx.MessageDialog(None,"Are you Sure to Quit?","Question", wx.YES_NO|wx.NO_DEFAULT|wx.ICON_QUESTION) ret = dial.ShowModal() if ret == wx.ID_YES: self.Destroy() else: e.Veto() if __name__ == '__main__': app = wx.App() Example(None,title="VetoMethod") app.MainLoop()
事件传播
有两种类型的事件:基本事件和命令事件。他们有着不同的传播方法。基本事件不传播。命令事件可能传播。例如wx.CloseEvent是一个基本的事件。它并不适合这个事件传播到父窗口小部件。
默认情况下,事件,是在一个事件处理程序可以停止传播。如果要继续传播,我们必须调用Skip()方法。
import wx class MyPanel(wx.Panel): def __init__(self,*args,**kw): super(MyPanel,self).__init__(*args,**kw) self.Bind(wx.EVT_BUTTON, self.OnButtonClicked) def OnButtonClicked(self,e): print "event reached panel class" e.Skip() class MyButton(wx.Button): def __init__(self,*args,**kw): super(MyButton,self).__init__(*args,**kw) self.Bind(wx.EVT_BUTTON, self.OnButtonClicked) def OnButtonClicked(self,e): print "event reached button class" e.Skip() class Example(wx.Frame): def __init__(self,*args,**kw): super(Example,self).__init__(*args,**kw) self.InitUI() def InitUI(self): mpnl = MyPanel(self) MyButton(mpnl,label='Ok',pos=(15,15)) self.Bind(wx.EVT_BUTTON, self.OnButtonClicked) self.SetTitle("Propagation") self.Centre() self.Show() def OnButtonClicked(self,e): print "event reached frame class" e.Skip() def main(): ex = wx.App() Example(None) ex.MainLoop() if __name__ == '__main__': main()
event reached button class event reached panel class event reached frame class
组件的ID
识符是整数,惟一确定组件身份的事件系统。有三种方法可以创建的窗口id。
1.让系统自动创建。
2.使用标准ID
3.自己创建
wx.Button(parent, -1) wx.Button(parent, wx.ID_ANY)
import wx class Example(wx.Frame): def __init__(self,*args,**kw): super(Example,self).__init__(*args,**kw) self.InitUI() def InitUI(self): panel = wx.Panel(self) grid = wx.GridSizer(3,2) grid.AddMany([(wx.Button(panel,wx.ID_CANCEL),0,wx.TOP|wx.LEFT,9), (wx.Button(panel, wx.ID_DELETE), 0, wx.TOP, 9), (wx.Button(panel, wx.ID_SAVE), 0, wx.LEFT, 9), (wx.Button(panel, wx.ID_EXIT)), (wx.Button(panel, wx.ID_STOP), 0, wx.LEFT, 9), (wx.Button(panel, wx.ID_NEW))]) self.Bind(wx.EVT_BUTTON, self.OnQuitApp,id=wx.ID_EXIT) panel.SetSizer(grid) self.SetSize((220,180)) self.SetTitle("window ID") self.Centre() self.Show() def OnQuitApp(self, event): self.Close() def main(): ex = wx.App() Example(None) ex.MainLoop() if __name__ == '__main__': main()
self.Bind(wx.EVT_BUTTON, self.OnQuitApp, id=wx.ID_EXIT)指定ID后,像这个id=wx.ID_EXIT。就可以处理它的事件了。
创建自己的ID
让我们来看看自己如何创建ID:
''' Created on 2012-7-5 @author: Administrator ''' import wx ID_MENU_NEW = wx.NewId() ID_MENU_OPEN = wx.NewId() ID_MENU_SAVE = wx.NewId() class Example(wx.Frame): def __init__(self,*args,**kw): super(Example,self).__init__(*args,**kw) self.InitUI() def InitUI(self): self.CreateStatusBar() self.CreateMenuBar() self.SetSize((250, 180)) self.SetTitle('My Own ID') self.Centre() self.Show(True) def CreateMenuBar(self): mb = wx.MenuBar() fMenu = wx.Menu() fMenu.Append(ID_MENU_NEW,'New') fMenu.Append(ID_MENU_OPEN, 'Open') fMenu.Append(ID_MENU_SAVE, 'Save') mb.Append(fMenu,'&File') self.SetMenuBar(mb) self.Bind(wx.EVT_MENU, self.DisplayMessage,id=ID_MENU_NEW) self.Bind(wx.EVT_MENU, self.DisplayMessage,id=ID_MENU_OPEN) self.Bind(wx.EVT_MENU, self.DisplayMessage,id=ID_MENU_SAVE) def DisplayMessage(self,e): sb = self.GetStatusBar() eid = e.GetId() if eid == ID_MENU_NEW: msg = 'New Menu item selected' elif eid==ID_MENU_OPEN: msg = 'Open menu item selected' elif eid == ID_MENU_SAVE: msg = 'Save menu item selected' sb.SetStatusText(msg) def main(): ex = wx.App() Example(None) ex.MainLoop() if __name__ == '__main__': main()
ID_MENU_NEW = wx.NewId() ID_MENU_OPEN = wx.NewId() ID_MENU_SAVE = wx.NewId()
重绘事件
我们窗口变大变小时或当我们最大化时,就会产生一个重绘事件。
import wx class Example(wx.Frame): def __init__(self, *args, **kw): super(Example, self).__init__(*args, **kw) self.InitUI() def InitUI(self): self.count = 0 self.Bind(wx.EVT_PAINT, self.OnPaint) self.SetSize((250, 180)) self.Centre() self.Show(True) def OnPaint(self,e): self.count += 1 self.SetTitle(str(self.count)) def main(): ex = wx.App() Example(None) ex.MainLoop() if __name__ == '__main__': main()
''' Created on 2012-7-5 @author: Administrator ''' import wx class MyWindow(wx.Panel): def __init__(self,parent): super(MyWindow,self).__init__(parent) self.color = '#b3b3b3' self.Bind(wx.EVT_PAINT, self.OnPaint) self.Bind(wx.EVT_SIZE, self.OnSize) self.Bind(wx.EVT_SET_FOCUS, self.OnSetFocus) self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus) def OnPaint(self,e): dc = wx.PaintDC(self) dc.SetPen(wx.Pen(self.color)) x,y = self.GetSize() dc.DrawRectangle(0,0,x,y) def OnSize(self,e): self.Refresh() def OnSetFocus(self,e): self.color = '#0099f7' self.Refresh() def OnKillFocus(self,e): self.color = '#b3b3b3' self.Refresh() class Example(wx.Frame): def __init__(self,*args,**kw): super(Example,self).__init__(*args,**kw) self.InitUI() def InitUI(self): grid = wx.GridSizer(2,2,10,10) grid.AddMany([(MyWindow(self),0,wx.EXPAND|wx.TOP|wx.LEFT,9), (MyWindow(self), 0, wx.EXPAND|wx.TOP|wx.RIGHT, 9), (MyWindow(self), 0, wx.EXPAND|wx.BOTTOM|wx.LEFT, 9), (MyWindow(self), 0, wx.EXPAND|wx.BOTTOM|wx.RIGHT, 9)]) self.SetSizer(grid) self.SetSize((350, 250)) self.SetTitle('Focus event') self.Centre() self.Show(True) def main(): ex = wx.App() Example(None) ex.MainLoop() if __name__ == '__main__': main()上面例子中,四个panel,最亮的那个panel就是焦点。
键盘事件
当你敲击键盘时,键盘事件就产生了。它针对的就是当前获得焦点的控件。有三种不同的处理方法:
wx.EVT_KEY_DOWN
wx.EVT_KEY_UP
wx.EVT_CHAR
我们来看一下这个例子,当你按下Esc键时,来关闭程序。
import wx class Example(wx.Frame): def __init__(self, *args, **kw): super(Example, self).__init__(*args, **kw) self.InitUI() def InitUI(self): pnl = wx.Panel(self) pnl.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown) pnl.SetFocus() self.SetSize((250, 180)) self.SetTitle('Key event') self.Centre() self.Show(True) def OnKeyDown(self,e): key = e.GetKeyCode() if key == wx.WXK_ESCAPE: ret = wx.MessageBox("Are you sure to quit?","Question", wx.YES_NO|wx.NO_DEFAULT,self) if ret == wx.YES: self.Close() def main(): ex = wx.App() Example(None) ex.MainLoop()