Jusene's Blog

Python GUI编程学习之wxPython(二)

字数统计: 2.8k阅读时长: 13 min
2017/12/30 Share

事件处理

不像控制台的程序,一个基于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提供了布局类的容器内的小部件的定位更优雅的管理,布局管理器使用绝对定位的优点是:

  • 在窗口中的窗口小部件会自动调整大小。
  • 确保均匀的外观上不同分辨率的显示设备。
  • 添加或去除部件动态地是可能的,而不需要重新设计。
CATALOG
  1. 1. 事件处理
  2. 2. 布局
    1. 2.1. BoxSizer布局
    2. 2.2. GridSizer布局
    3. 2.3. FlexiGridSizer布局
    4. 2.4. GridBagSizer布局
    5. 2.5. StaticBoxSizer布局