事件处理
不像控制台的程序,一个基于GUI的应用程序是事件驱动,这是在一个顺序的方式执行,有关某个事件其中应用程序的运行时期间发生的数据被存储为来自wx.Event衍生的子类的对。象
1 | self.b1.Bind(事件处理器,处理方法) |
1 | import wx |
2 | |
3 | class Mywin(wx.Frame): |
4 | def __init__(self,*args,**kwargs): |
5 | super(Mywin,self).__init__(*args,**kwargs) |
6 | self.InitUI() |
7 | |
8 | def InitUI(self): |
9 | panel=wx.Panel(self) |
10 | box=wx.BoxSizer(wx.VERTICAL) |
11 | self.label=wx.StaticText(panel,label='window position',style=wx.ALIGN_CENTER) |
12 | box.Add(self.label,0,wx.EXPAND|wx.ALIGN_CENTER_HORIZONTAL|wx.ALL) |
13 | self.Bind(wx.EVT_MOVE,self.OnMove) |
14 | self.SetSize((300,200)) |
15 | self.SetTitle('Move event') |
16 | self.Center() |
17 | self.Show() |
18 | def OnMove(self,event): |
19 | x,y=event.GetPosition() |
20 | self.label.SetLabel('current window position x = '+str(x)+" y = "+str(y))) |
21 | if __name__ == "__main__": |
22 | app=wx.App() |
23 | Mywin(None) |
24 | app.MainLoop() |
一些来之wx.EVENT继承子类的反复:
- wx.KeyEvent 当一个键被按下或释放时发生
- wx.PainEvent 当需要重绘窗口的内容时发生
- wx.MouseEvent 包含有关事件,由于鼠标活动数据,如按钮鼠标按钮或拖动
- wx.ScrollEvent 关联wx.Scrollbar和wx.Slider滚动控制
- wx.CommandEvent 包含事件数据来自许多构件,如按钮,对话框,剪切板等
- wx.MenuEvent 不同的菜单相关的事件但不包括菜单命令按钮
- wx.ColourPickerEvent wx.ColourPickerCtrl生成的事件
- wx.DirFilePickerEvent 通过FileDialog和DirDialog生成的事件
wxPython中事件是两种类型的,基本事件和命令事件,一个基本事件停留在它起源的窗口,大多数wxWidgets生成命令事件,命令事件可以传播到一个或多个窗口,类层次结构来源于窗口上方。
1 | import wx |
2 | |
3 | class MyPanel(wx.Panel): |
4 | def __init__(self,parent): |
5 | super(MyPanel,self).__init__(parent) |
6 | b=wx.Button(self,label='Button') |
7 | b.Bind(wx.EVT_BUTTON,self.btnclk) |
8 | self.Bind(wx.EVT_BUTTON,self.OnButtonClicked) |
9 | |
10 | def OnButtonClicked(self,event): |
11 | print('Panel received clicked event') |
12 | event.Skip() |
13 | def btnclk(self,event): |
14 | print('Button received click event') |
15 | event.Skip() |
16 | |
17 | class Mywin(wx.Frame): |
18 | def __init__(self,parent): |
19 | super(Mywin,self).__init__(parent) |
20 | self.InitUI() |
21 | def InitUI(self): |
22 | mpn1=MyPanel(self) |
23 | self.Bind(wx.EVT_BUTTON,self.OnButtonClicked) |
24 | |
25 | self.SetTitle('Event demo') |
26 | self.Center() |
27 | self.Show() |
28 | |
29 | def OnButtonClicked(self,e): |
30 | print('click event received by frame class') |
31 | e.Skip() |
32 | |
33 | if __name__ == "__main__": |
34 | app=wx.App() |
35 | Mywin(None) |
36 | app.MainLoop() |
此按钮对象绑定到事件的处理程序btnclk(),它传播到他的父类,按一下按钮生成可被Skip()方法来传递到父CommandEvent。
布局
BoxSizer布局
BoxSizer允许控件排放在按行或列的方式:
1 | Box=wx.BoxSizer(wx.HORIZONTAL) 水平布局 |
2 | Box=wx.BoxSizer(wx.VERTICAL) 垂直布局 |
1 | Box.Add(control,proportion,flag,border) |
proportion参数控制的控件响应于所述容器的尺寸改变其大小,各种flag参数的组合决定控制在sizer的外观。
flag
对齐标志
wx.ALIGN_TOP
wx.ALIGN_BOTTOM
wx.ALIGN_LEFT
wx.ALIGN_RIGHT
wx.ALIGN_CENTER_VERTICAL
wx.ALIGN_CENTER_HORIZONTAL边界标志
wx.TOP
wx.BOTTOM
wx.LEFT
wx.RIGHT
wx.ALL行为标志
wx.EXPAND 项目将扩大,以填补提供给它的空间
wx.SHAPED 与EXPAND相似,但保持了项目的高宽比
wx.FIXED_MINSIZE 不允许该项目变得比其最初的最小尺寸更小
wx.RESERVER_SPACE_EVEN_IF_HIDDEN 不允许sizer回收项目空间,当它被隐藏时
wx.BoxSizer类的一些方法:
- setOrientation() 设置定向wx.HORIZONTAL或wx.VERTICAL
- AddSpacer() 添加非伸缩性空间
- AddStretchSpacer() 增加了伸缩空间,以便调整窗口的大小会影响控件的大小成比例
- Clear() 从sizer移除子控件
- Detach() 从sizer删除控件不销毁
- Insert() 在指定位置插入一个子控件
- Remove() 从sizer和销毁删除子控件
1 | import wx |
2 | |
3 | class Mywin(wx.Frame): |
4 | def __init__(self,parent,title): |
5 | super(Mywin,self).__init__(parent,title=title,size=(200,300)) |
6 | self.InitUI() |
7 | def InitUI(self): |
8 | panel=wx.Panel(self) |
9 | vbox=wx.BoxSizer(wx.VERTICAL) |
10 | l1=wx.StaticText(panel,label='Enter a number',style=wx.ALIGN_LEFT) |
11 | vbox.Add(l1,0,wx.ALL|wx.EXPAND|wx.ALIGN_LEFT,20) |
12 | |
13 | b1=wx.Button(panel,label='Button1') |
14 | vbox.Add(b1,0,wx.EXPAND) |
15 | |
16 | b2=wx.Button(panel,label='Button2') |
17 | vbox.Add(b2,0,wx.ALIGN_CENTER_HORIZONTAL) |
18 | |
19 | t3=wx.TextCtrl(panel,-1,size=(200,50),style=wx.TE_MULTILINE) |
20 | vbox.Add(t3,0,wx.EXPAND,10) |
21 | |
22 | hbox=wx.BoxSizer(wx.HORIZONTAL) |
23 | l4=wx.StaticText(panel,label='label1',style=wx.ALIGN_CENTER) |
24 | l5=wx.StaticText(panel,label='label2',style=wx.ALIGN_CENTER) |
25 | hbox.Add(l4,1,wx.EXPAND) |
26 | hbox.AddStretchSpacer(10) |
27 | hbox.Add(l5,1,wx.ALIGN_RIGHT,20) |
28 | vbox.Add(hbox) |
29 | panel.SetSizer(vbox) |
30 | self.Center() |
31 | self.Show() |
32 | if __name__ == "__main__": |
33 | app=wx.App() |
34 | Mywin(None,'Demo') |
35 | app.MainLoop() |
GridSizer布局
GridSizer对象展示二维网格:
1 | wx.GridSizer(rows,clumns,vgap,hgap) |
vgap和hgap指定控制相邻控件之间的纵向和横向间距。
wx.GridSizer类方法:
- Add() 添加在向一可用网格插槽控件
- AddMany() 在控制列表中添加每个项目
- SetRows() 设置sizer中行数
- GetRows() 检索sizer中行数
- SetCols() 设置sizer列数
- GetCols() 检索sizer列数
- SetVGap() 设定单元之间垂直间隙
- GetVGap() 返回vgap值
- SetHGap() 设置单元之间的水平间隙
- GetHGap() 返回指定的小区之间的hgap值
1 | import wx |
2 | |
3 | class Mywin(wx.Frame): |
4 | def __init__(self,parent,title): |
5 | super(Mywin,self).__init__(parent,title=title,size=(300,200)) |
6 | self.InitUI() |
7 | def InitUI(self): |
8 | panel=wx.Panel(self) |
9 | gs=wx.GridSizer(4,4,5,5) |
10 | |
11 | for i in range(1,17): |
12 | btn='Button'+str(i) |
13 | gs.Add(wx.Button(panel,label=btn),0,wx.EXPAND) |
14 | |
15 | panel.SetSizer(gs) |
16 | self.Center() |
17 | self.Show() |
18 | if __name__ == "__main__": |
19 | app=wx.App() |
20 | Mywin(None,title='grid demo') |
21 | app.MainLoop() |
FlexiGridSizer布局
这种大小测定器也是一个二维网格,然而 ,它提供多一点灵活性布局控件在单元中。尽管同一行中的所有控件具有相同的高度,并且在同一列中的所有控件具有相同宽度,但是每个小区大小是不均匀的。
宽度和/或单元格在单个列中的高度/行可以通过AddGrowableRow()和AddGrowableCol()方法来扩展。
1 | wx.FlexiGridSizer(rows,cols,vgap,hgap) |
类方法:
AddGrowableCol() 指定索引的列增长
AddGrowRow() 指定索引的行增长
SetFlexibleDirection() 指定大小测量器的灵活性是否影响行,列
1 | import wx |
2 | |
3 | class Mywin(wx.Frame): |
4 | def __init__(self,parent,title): |
5 | super(Mywin,self).__init__(parent,title=title,size=(400,250)) |
6 | self.InitUI() |
7 | def InitUI(self): |
8 | panel=wx.Panel(self) |
9 | hbox=wx.BoxSizer(wx.HORIZONTAL) |
10 | fgs=wx.FlexGridSizer(3,2,10,10) |
11 | |
12 | title=wx.StaticText(panel,label='Title') |
13 | author=wx.StaticText(panel,label='Name of the Author') |
14 | review=wx.StaticText(panel,label='Review') |
15 | |
16 | tc1=wx.TextCtrl(panel) |
17 | tc2=wx.TextCtrl(panel) |
18 | tc3=wx.TextCtrl(panel,style=wx.TE_MULTILINE) |
19 | |
20 | fgs.AddMany([(title),(tc1,1,wx.EXPAND),(author),(tc2,1,wx.EXPAND),(review,1,wx.EXPAND),(tc3,1,wx.EXPAND)]) |
21 | fgs.AddGrowableRow(2, 1) |
22 | fgs.AddGrowableCol(1, 1) |
23 | hbox.Add(fgs,proportion=2,flag=wx.ALL|wx.EXPAND,border=15) |
24 | panel.SetSizer(hbox) |
25 | self.Center() |
26 | self.Show() |
27 | if __name__ == "__main__": |
28 | app=wx.App() |
29 | Mywin(None,title='FlexiGrid') |
30 | app.MainLoop() |
用下面的代码设计两列表单。 第一列包含标签和第二个包含文本框。第二列被设定为可增长。类似地,第三行被设定为可增长。(请注意,行索引和列索引从0开始)。在AddGrowableCol()和AddGrowableRow()函数的第二个参数是proportion增长。
1 | fgs.AddGrowableRow(2, 1) |
2 | fgs.AddGrowableCol(1, 1) |
GridBagSizer布局
GridBagSizer是一种多功能大小测定器。它比FlexiGridSizer提供了更多的增强功能。子构件可被添加到网格中的特定单元。此外,一个子物件可以在水平或垂直地占据一个以上的单元。
1 | wx.GridBagSizer(vgap,hgap) |
GridBagSizer类最重要的方法是Add(),它接受位置作为强制性参数。
1 | wx.GridbagSizer.Add(control,pos,span,flags,border) |
类方法:
Add() 在网格中指定位置增加给定控件
GetItemPosition() 返回在网格的控件的位置
SetItemPosition() 在网格中指定位置放置一个控件
GetItemSpan() 返回一个项目的行/列跨越
SetItemSpan() 跨越指定的项目超过行/列数
1 | import wx |
2 | |
3 | class Mywin(wx.Frame): |
4 | def __init__(self,parent,title): |
5 | super(Mywin,self).__init__(parent,title=title) |
6 | self.InitUI() |
7 | self.Center() |
8 | self.Show() |
9 | |
10 | def InitUI(self): |
11 | panel=wx.Panel(self) |
12 | sizer=wx.GridBagSizer(0,0) |
13 | |
14 | text=wx.StaticText(panel,label='Name:') |
15 | sizer.Add(text,pos=(0,0),flag=wx.ALL,border=5) |
16 | |
17 | tc=wx.TextCtrl(panel) |
18 | sizer.Add(tc,pos=(0,1),span=(1,2),flag=wx.EXPAND|wx.ALL,border=5) |
19 | |
20 | text1=wx.StaticText(panel,label='address:') |
21 | sizer.Add(text1,pos=(1,0),flag=wx.ALL,border=5) |
22 | |
23 | tc1=wx.TextCtrl(panel) |
24 | sizer.Add(tc1,pos=(1,1),span=(1,3),flag=wx.EXPAND|wx.ALL,border=5) |
25 | |
26 | text2=wx.StaticText(panel,label='age:') |
27 | sizer.Add(text2,pos=(2,0),flag=wx.ALL,border=5) |
28 | |
29 | tc2=wx.TextCtrl(panel) |
30 | sizer.Add(tc2,pos=(2,1),flag=wx.ALL,border=5) |
31 | |
32 | text3=wx.StaticText(panel,label='Mob.No') |
33 | sizer.Add(text3,pos=(2,2),flag=wx.ALIGN_CENTER|wx.ALL,border=5) |
34 | |
35 | tc3=wx.TextCtrl(panel) |
36 | sizer.Add(tc3,pos=(2,3),flag=wx.ALL,border=5) |
37 | |
38 | text4=wx.StaticText(panel,label='Description') |
39 | sizer.Add(text4,pos=(3,0),flag=wx.ALL,border=5) |
40 | |
41 | tc4=wx.TextCtrl(panel,style=wx.TE_MULTILINE) |
42 | sizer.Add(tc4,pos=(3,1),span=(1,3),flag=wx.EXPAND|wx.ALL,border=5) |
43 | sizer.AddGrowableRow(3) |
44 | |
45 | buttonOK=wx.Button(panel,label='OK') |
46 | buttonClose=wx.Button(panel,label='Close') |
47 | |
48 | sizer.Add(buttonOK,pos=(4,2),flag=wx.ALL,border=5) |
49 | sizer.Add(buttonClose,pos=(4,3),flag=wx.ALL,border=5) |
50 | |
51 | panel.SetSizerAndFit(sizer) |
52 | |
53 | if __name__ == "__main__": |
54 | app=wx.App() |
55 | Mywin(None,title='GridBag') |
56 | app.MainLoop() |
StaticBoxSizer布局
StaticBoxSizer把一个盒子大小测定器到静态框。它提供了围绕框边界连同在顶部的标签,涉及准备statixboxsizer以下步骤:
- 创建一个wx.StaticBox对象
- 声明一个wx.StaticBoxSizer与上面的静态框作为其参数
- 创建控件并添加到staticbox大小测定器
- 设置为大小测定器的框架
1 | import wx |
2 | |
3 | class Mywin(wx.Frame): |
4 | def __init__(self,parent,title): |
5 | super(Mywin,self).__init__(parent,title=title) |
6 | panel=wx.Panel(self) |
7 | vbox=wx.BoxSizer(wx.VERTICAL) |
8 | nm=wx.StaticBox(panel,-1,'Name') |
9 | nmSizer=wx.StaticBoxSizer(nm,wx.VERTICAL) |
10 | |
11 | nmbox=wx.BoxSizer(wx.HORIZONTAL) |
12 | fn=wx.StaticText(panel,-1,'First Name') |
13 | nmbox.Add(fn,0,wx.ALL|wx.CENTER,5) |
14 | nm1=wx.TextCtrl(panel,-1,style=wx.ALIGN_LEFT) |
15 | nm2=wx.TextCtrl(panel,-1,style=wx.ALIGN_LEFT) |
16 | ln=wx.StaticText(panel,-1,'Last Name') |
17 | nmbox.Add(nm1,0,wx.ALL|wx.CENTER,5) |
18 | nmbox.Add(ln,0,wx.ALL|wx.CENTER,5) |
19 | nmbox.Add(nm2,0,wx.ALL|wx.CENTER,5) |
20 | nmSizer.Add(nmbox,0,wx.ALL|wx.CENTER,10) |
21 | |
22 | sbox=wx.StatixBox(panel,-1,'Button') |
23 | sboxSizer=wx.StaticBoxSizer(sbox,wx.VERTICAL) |
24 | |
25 | hbox=wx.BoxSizer(wx.HORIZONTAL) |
26 | okButton=wx.Button(panel,-1,'ok') |
27 | calcelButton=wx.Button(panel,-1,'cancel') |
28 | hbox.Add(okButton,0,wx.ALL|wx.LEFT,10) |
29 | hbox.Add(calcelButton,0,wx.ALL|wx.LEFT,10) |
30 | sboxSizer.Add(hbox,0,wx.ALL|wx.LEFT,10) |
31 | vbox.Add(nmSizer,0,wx.ALL|wx.CENTER,5) |
32 | vbox.Add(sboxSizer,0,wx.ALL|wx.CENTER,5) |
33 | panel.SetSizer(vbox) |
34 | self.Center() |
35 | self.Show() |
36 | panel.Fit() |
37 | |
38 | if __name__ == "__main__": |
39 | app=wx.App() |
40 | Mywin(None,'StaticBoxSizer') |
41 | app.MainLoop() |
一个GUI部件可通过指定以像素为单位的绝对坐标放置在容器窗口,坐标是相对于它的构造尺寸参数定义的窗口大小,窗口中的窗口小部件的位置由它的构造函数的pos参数定义的。
绝对定位不适合下列原因:
- 小部件的位置,如果调整窗口的大小也不会改变。
- 外观可能不是均匀的,在具有不同的分辨率不同的显示设备。
- 修改中的布局是困难的,因为它可能需要重新设计整个表格。
wxPython的API提供了布局类的容器内的小部件的定位更优雅的管理,布局管理器使用绝对定位的优点是:
- 在窗口中的窗口小部件会自动调整大小。
- 确保均匀的外观上不同分辨率的显示设备。
- 添加或去除部件动态地是可能的,而不需要重新设计。