转自:http://thisis.yorven.site/blog/index.php/2017/09/23/wxpython-jiaocheng-widgets/#wxButton
在本节中,我们将介绍基本的 wxPython widgets。每一个 widget 将会有一个小例子介绍。Widgets 是 应用的基本单元,wxPython 有很多基本 widgets:按钮、选择框、滑动器、列表框等。

wx.Button

wx.Button 是一个简单的 widget,仅包含一个文本字符串,用来触发某个动作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#!/usr/bin/python
# -*- coding: utf-8 -*-

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)
cbtn = wx.Button(pnl, label='Close', pos=(20, 30))

cbtn.Bind(wx.EVT_BUTTON, self.OnClose)

self.SetSize((250, 200))
self.SetTitle('wx.Button')
self.Centre()
self.Show(True)

def OnClose(self, e):

self.Close(True)

def main():

ex = wx.App()
Example(None)
ex.MainLoop()


if __name__ == '__main__':
main()

在样例中,我们创建了一个 Close 按键,点击 Close 即可关闭应用。

1
cbtn = wx.Button(pnl, label='Close', pos=(20, 30))

在按钮的构造函数中,我们提供了按钮的文本标签以及它在 panel 上的位置。

1
cbtn.Bind(wx.EVT_BUTTON, self.OnClose)

当点击按钮时 wx.EVT_BUTTON 事件会被触发,我们定义了 OnClose() 方法来处理该事件。

1
2
3
def OnClose(self, e):

self.Close(True)

在 OnClose() 函数中,我们调用了 Close() 函数来关闭应用。
wx.Button

wx.ToggleButton

wx.ToggleButton 也是一种按钮,但它有两个状态:点击和非点击状态。通过点击按键可以在两种状态中切换。在特定场景中,这一功能将非常适用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#!/usr/bin/python
# -*- coding: utf-8 -*-

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)

self.col = wx.Colour(0, 0, 0)

rtb = wx.ToggleButton(pnl, label='red', pos=(20, 25))
gtb = wx.ToggleButton(pnl, label='green', pos=(20, 60))
btb = wx.ToggleButton(pnl, label='blue', pos=(20, 100))

self.cpnl = wx.Panel(pnl, pos=(150, 20), size=(110, 110))
self.cpnl.SetBackgroundColour(self.col)

rtb.Bind(wx.EVT_TOGGLEBUTTON, self.ToggleRed)
gtb.Bind(wx.EVT_TOGGLEBUTTON, self.ToggleGreen)
btb.Bind(wx.EVT_TOGGLEBUTTON, self.ToggleBlue)

self.SetSize((300, 200))
self.SetTitle('Toggle buttons')
self.Centre()
self.Show(True)

def ToggleRed(self, e):

obj = e.GetEventObject()
isPressed = obj.GetValue()

green = self.col.Green()
blue = self.col.Blue()

if isPressed:
self.col.Set(255, green, blue)
else:
self.col.Set(0, green, blue)

self.cpnl.SetBackgroundColour(self.col)
self.cpnl.Refresh()

def ToggleGreen(self, e):

obj = e.GetEventObject()
isPressed = obj.GetValue()

red = self.col.Red()
blue = self.col.Blue()

if isPressed:
self.col.Set(red, 255, blue)
else:
self.col.Set(red, 0, blue)

self.cpnl.SetBackgroundColour(self.col)
self.cpnl.Refresh()

def ToggleBlue(self, e):

obj = e.GetEventObject()
isPressed = obj.GetValue()

red = self.col.Red()
green = self.col.Green()

if isPressed:
self.col.Set(red, green, 255)
else:
self.col.Set(red, green, 0)

self.cpnl.SetBackgroundColour(self.col)
self.cpnl.Refresh()


def main():

ex = wx.App()
Example(None)
ex.MainLoop()


if __name__ == '__main__':
main()

我们创建了红色、绿色和蓝色的 Toggle button 和一个 Panel。点击 toggle button的时候,可以改变 panel 的颜色。

1
rtb = wx.ToggleButton(pnl, label='red', pos=(20, 25))

上面的代码创建了一个 wx.ToggleButton 部件。

1
2
self.cpnl  = wx.Panel(pnl, pos=(150, 20), size=(110, 110))
self.cpnl.SetBackgroundColour(self.col)

新建了一个 Panel,颜色设置为 self.col。

1
rtb.Bind(wx.EVT_TOGGLEBUTTON, self.ToggleRed)

当我们点击 rtb 这个触发 button 的时候 ToggleRed() 会被调用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def ToggleRed(self, e):

obj = e.GetEventObject()
isPressed = obj.GetValue()

green = self.col.Green()
blue = self.col.Blue()

if isPressed:
self.col.Set(255, green, blue)
else:
self.col.Set(0, green, blue)

self.cpnl.SetBackgroundColour(self.col)

在 ToogleRed() 函数里,我们对 rtb 按钮是否被按下做出反应,来改变特定 panel 的颜色。
触发按钮

wx.StaticLine

这个 widget 在窗口上展示一个简单的直线,可以是竖直或水平的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#!/usr/bin/python
# -*- coding: utf-8 -*-

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)

font = wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD)
heading = wx.StaticText(self, label='The Central Europe', pos=(130, 15))
heading.SetFont(font)

wx.StaticLine(self, pos=(25, 50), size=(300,1))

wx.StaticText(self, label='Slovakia', pos=(25, 80))
wx.StaticText(self, label='Hungary', pos=(25, 100))
wx.StaticText(self, label='Poland', pos=(25, 120))
wx.StaticText(self, label='Czech Republic', pos=(25, 140))
wx.StaticText(self, label='Germany', pos=(25, 160))
wx.StaticText(self, label='Slovenia', pos=(25, 180))
wx.StaticText(self, label='Austria', pos=(25, 200))
wx.StaticText(self, label='Switzerland', pos=(25, 220))

wx.StaticText(self, label='5 445 000', pos=(250, 80))
wx.StaticText(self, label='10 014 000', pos=(250, 100))
wx.StaticText(self, label='38 186 000', pos=(250, 120))
wx.StaticText(self, label='10 562 000', pos=(250, 140))
wx.StaticText(self, label='81 799 000', pos=(250, 160))
wx.StaticText(self, label='2 050 000', pos=(250, 180))
wx.StaticText(self, label='8 414 000', pos=(250, 200))
wx.StaticText(self, label='7 866 000', pos=(250, 220))

wx.StaticLine(self, pos=(25, 260), size=(300,1))

tsum = wx.StaticText(self, label='164 336 000', pos=(240, 280))
sum_font = tsum.GetFont()
sum_font.SetWeight(wx.BOLD)
tsum.SetFont(sum_font)

btn = wx.Button(self, label='Close', pos=(140, 310))

btn.Bind(wx.EVT_BUTTON, self.OnClose)

self.SetSize((360, 380))
self.SetTitle('wx.StaticLine')
self.Centre()
self.Show(True)

def OnClose(self, e):

self.Close(True)

def main():

ex = wx.App()
Example(None)
ex.MainLoop()

if __name__ == '__main__':
main()

上面的脚本展示了中欧的国家和他们的人口, wx.StaticLine 让界面更加美观。

1
wx.StaticLine(self, pos=(25, 50), size=(300,1))

上面是 wx.StaticLine 的构造函数。
wx.StaticLine

wx.StaticText

wx.StaticText 展示一行或多行的只读文本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#!/usr/bin/python
# -*- coding: utf-8 -*-

import wx


class Example(wx.Frame):

def __init__(self, *args, **kw):
super(Example, self).__init__(*args, **kw)

self.InitUI()

def InitUI(self):

txt1 = '''I'm giving up the ghost of love
in the shadows cast on devotion
She is the one that I adore
creed of my silent suffocation
Break this bittersweet spell on me
lost in the arms of destiny'''

txt2 = '''There is something in the way
You're always somewhere else
Feelings have deserted me
To a point of no return
I don't believe in God
But I pray for you'''

pnl = wx.Panel(self)
vbox = wx.BoxSizer(wx.VERTICAL)

st1 = wx.StaticText(pnl, label=txt1, style=wx.ALIGN_CENTRE)
st2 = wx.StaticText(pnl, label=txt2, style=wx.ALIGN_CENTRE)

vbox.Add(st1, flag=wx.ALL, border=5)
vbox.Add(st2, flag=wx.ALL, border=5)
pnl.SetSizer(vbox)

self.SetSize((250, 260))
self.SetTitle('Bittersweet')
self.Centre()
self.Show(True)

def main():

ex = wx.App()
Example(None)
ex.MainLoop()

if __name__ == '__main__':
main()

在上面的例子中,我们展示了一首 Bittersweet 歌曲的两节歌词。

1
2
3
4
5
6
        txt1 = '''I'm giving up the ghost of love
in the shadows cast on devotion
She is the one that I adore
creed of my silent suffocation
Break this bittersweet spell on me
lost in the arms of destiny'''

上面是要在 wx.StaticText 展示的字符串。

1
st1 = wx.StaticText(pnl, label=txt1, style=wx.ALIGN_CENTRE)

我们创建了 wx.StaticText 部件,文字被居中展示。
wx.StaticText

wx.StaticBox

这是一个装饰部件,被用来逻辑上将一组部件包括起来。需要注意的是,该部件必须在它所包含的部件创建之前创建,且那些被包含的部件是 wx.StaticBox 的兄弟部件而非子部件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#!/usr/bin/python
# -*- coding: utf-8 -*-

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)

wx.StaticBox(pnl, label='Personal Info', pos=(5, 5), size=(240, 170))
wx.CheckBox(pnl, label='Male', pos=(15, 30))
wx.CheckBox(pnl, label='Married', pos=(15, 55))
wx.StaticText(pnl, label='Age', pos=(15, 95))
wx.SpinCtrl(pnl, value='1', pos=(55, 90), size=(60, -1), min=1, max=120)

btn = wx.Button(pnl, label='Ok', pos=(90, 185), size=(60, -1))

btn.Bind(wx.EVT_BUTTON, self.OnClose)

self.SetSize((270, 250))
self.SetTitle('Static box')
self.Centre()
self.Show(True)

def OnClose(self, e):

self.Close(True)


def main():

ex = wx.App()
Example(None)
ex.MainLoop()


if __name__ == '__main__':
main()

上面的例子中,我们创建了一个 wx.StaticBox,它装饰了其他的 4 个部件。
Static box

wx.ComboBox

wx.ComboBox 是由一行文本域、一个带有下拉箭头图标的按钮和一个列表框所构成的部件。当你按下按钮时,将出现一个列表框,用户只可选择其中的一个选项。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#!/usr/bin/python
# -*- coding: utf-8 -*-

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)

distros = ['Ubuntu', 'Arch', 'Fedora', 'Debian', 'Mint']
cb = wx.ComboBox(pnl, pos=(50, 30), choices=distros,
style=wx.CB_READONLY)

self.st = wx.StaticText(pnl, label='', pos=(50, 140))
cb.Bind(wx.EVT_COMBOBOX, self.OnSelect)

self.SetSize((250, 230))
self.SetTitle('wx.ComboBox')
self.Centre()
self.Show(True)

def OnSelect(self, e):

i = e.GetString()
self.st.SetLabel(i)

def main():

ex = wx.App()
Example(None)
ex.MainLoop()

if __name__ == '__main__':
main()

被选择的选项将会显示在文本标签上。

1
distros = ['Ubuntu', 'Arch', 'Fedora', 'Debian', 'Mint']

单选框将包含以上列表的字符串。

1
2
cb = wx.ComboBox(pnl, pos=(50, 30), choices=distros, 
style=wx.CB_READONLY)

上面代表新建了 wx.ComboBox,通过 choices 参数传入一个字符串列表, wx.CB_READONLY 使得列表的字符串只读,即不可编辑。

1
cb.Bind(wx.EVT_COMBOBOX, self.OnSelect)

当从单选框选择一个选项时, wx.EVT_COMBOBOX 事件将被触发。我们绑定了 OnSelect() 来处理该事件。

1
2
3
4
def OnSelect(self, e):

i = e.GetString()
self.st.SetLabel(i)

从单选框选择一个条目并设置标签文本。
wx.ComboBox

wx.CheckBox

wx.CheckBox 只有两个状态:打开或关闭。它有一个框和文本标签组成,文本标签可以设置为放在框的左边或者右边。当 wx.CheckBox 被选择之后,框里将出现一个对号√。

在上面的例子中,我们通过一个 wx.CheckBox 部件来决定是否显示或隐藏窗口的标题。

1
cb = wx.CheckBox(pnl, label='Show title', pos=(20, 20))

上面是 wx.CheckBox 部件的构造函数。

1
cb.SetValue(True)

由于窗口的标题应该是被默认显示的,所以我们通过 SetValue() 方法默认选择 wx.CheckBox。

1
cb.Bind(wx.EVT_CHECKBOX, self.ShowOrHideTitle)

当点击 wx.CheckBox 部件时,wx.EVT_CHECKBOX 事件将被触发,我们将其绑定至事件处理器 ShowOrHideTitle() 函数。

1
2
3
4
5
6
7
8
9
def ShowOrHideTitle(self, e):

sender = e.GetEventObject()
isChecked = sender.GetValue()

if isChecked:
self.SetTitle('wx.CheckBox')
else:
self.SetTitle('')

在 ShowOrHideTitle() 方法中,我们通过 wx.CheckBox 的状态来决定是否隐藏或显示窗口的标题。
wx.CheckBox

wx.StatusBar

wx.StatusBar 用来展示应用的状态信息,可以被分成不同的部分来展示不同的信息。我们也可以把其他 widgets 插入到 wx.StatusBar 中。它可以作为 dialog 的替代选择,因为现在 dialog 被滥用,很多用户都不喜欢。我们可以通过两种方式新建 wx.StatusBar。可以直接创建 wx.StatusBar 然后调用 SetStatusBar() 函数,也可以简单的调用 CreateStatusBar() 函数即可,第二种方法创建了一个默认的 wx.StatusBar。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#!/usr/bin/python
# -*- coding: utf-8 -*-

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)

button = wx.Button(pnl, label='Button', pos=(20, 20))
text = wx.CheckBox(pnl, label='CheckBox', pos=(20, 90))
combo = wx.ComboBox(pnl, pos=(120, 22), choices=['Python', 'Ruby'])
slider = wx.Slider(pnl, 5, 6, 1, 10, (120, 90), (110, -1))

pnl.Bind(wx.EVT_ENTER_WINDOW, self.OnWidgetEnter)
button.Bind(wx.EVT_ENTER_WINDOW, self.OnWidgetEnter)
text.Bind(wx.EVT_ENTER_WINDOW, self.OnWidgetEnter)
combo.Bind(wx.EVT_ENTER_WINDOW, self.OnWidgetEnter)
slider.Bind(wx.EVT_ENTER_WINDOW, self.OnWidgetEnter)

self.sb = self.CreateStatusBar()

self.SetSize((250, 230))
self.SetTitle('wx.Statusbar')
self.Centre()
self.Show(True)

def OnWidgetEnter(self, e):

name = e.GetEventObject().GetClassName()
self.sb.SetStatusText(name + ' widget')
e.Skip()

def main():

ex = wx.App()
Example(None)
ex.MainLoop()

if __name__ == '__main__':
main()

在上面的例子中,我们新建了 wx.Frame 和 5 个其他的 widgets。如果我们把鼠标悬停在 widget 上面,它的名字将会被显示在 wx.StatusBar 上。

1
pnl.Bind(wx.EVT_ENTER_WINDOW, self.OnWidgetEnter)

当我们的鼠标进入到 widget 的区域时, EVT_ENTER_WINDOW 事件将被触发。

1
2
3
4
5
def OnWidgetEnter(self, e):

name = e.GetEventObject().GetClassName()
self.sb.SetStatusText(name + ' widget')
e.Skip()

在 OnWidgetEnter() 函数中,我们得到鼠标进入的 widget 的名字,然后使用 SetStatusText() 方法设置了状态栏的文字。
wx.StatusBar

wx.RadioButton

wx.RadioButton 允许用户从一组选项中排他的选择一个唯一选项。通过对第一个 radio 按钮设置 wx.RB_GROUP 样式标记,可以将紧随其后的其他 radio 按钮囊括为一组。随后的 radio 按钮如果也被设置了 wx.RB_GROUP 样式标记,那表明将开始新的一组选择框。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#!/usr/bin/python
# -*- coding: utf-8 -*-

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)

self.rb1 = wx.RadioButton(pnl, label='Value A', pos=(10, 10),
style=wx.RB_GROUP)
self.rb2 = wx.RadioButton(pnl, label='Value B', pos=(10, 30))
self.rb3 = wx.RadioButton(pnl, label='Value C', pos=(10, 50))

self.rb1.Bind(wx.EVT_RADIOBUTTON, self.SetVal)
self.rb2.Bind(wx.EVT_RADIOBUTTON, self.SetVal)
self.rb3.Bind(wx.EVT_RADIOBUTTON, self.SetVal)

self.sb = self.CreateStatusBar(3)

self.sb.SetStatusText("True", 0)
self.sb.SetStatusText("False", 1)
self.sb.SetStatusText("False", 2)

self.SetSize((210, 210))
self.SetTitle('wx.RadioButton')
self.Centre()
self.Show(True)

def SetVal(self, e):

state1 = str(self.rb1.GetValue())
state2 = str(self.rb2.GetValue())
state3 = str(self.rb3.GetValue())

self.sb.SetStatusText(state1, 0)
self.sb.SetStatusText(state2, 1)
self.sb.SetStatusText(state3, 2)

def main():

ex = wx.App()
Example(None)
ex.MainLoop()

if __name__ == '__main__':
main()

我们创建了一组 3 个 radio 按钮,每个按钮的状态被显示在 statusBar 上。

1
2
3
self.rb1 = wx.RadioButton(pnl, label='Value A', pos=(10, 10), style=wx.RB_GROUP)
self.rb2 = wx.RadioButton(pnl, label='Value B', pos=(10, 30))
self.rb3 = wx.RadioButton(pnl, label='Value C', pos=(10, 50))

上面的代码新建了 3 个 radio 按钮,其中第一个被设置了 wx.RB_GROUP 样式,表明接下来的 radio 都将是同一组。

1
self.rb1.Bind(wx.EVT_RADIOBUTTON, self.SetVal)

我们将 wx.EVT_RADIOBUTTON 事件绑定至 SetVal() 时间处理函数上。

1
2
3
4
5
self.sb = self.CreateStatusBar(3)

self.sb.SetStatusText("True", 0)
self.sb.SetStatusText("False", 1)
self.sb.SetStatusText("False", 2)

我们创建了分三部分的 statusbar,并根据对应 radio 的状态设置了初始文字。

1
2
3
4
5
6
7
8
9
def SetVal(self, e):

state1 = str(self.rb1.GetValue())
state2 = str(self.rb2.GetValue())
state3 = str(self.rb3.GetValue())

self.sb.SetStatusText(state1, 0)
self.sb.SetStatusText(state2, 1)
self.sb.SetStatusText(state3, 2)

在 SetVal() 函数中,我们对状态栏的文本进行了更新。
wx.RadioButton

wx.Gauge

wx.Gauge 主要用在时间较长的任务场景,用来显示当前任务的状态。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#!/usr/bin/python
# -*- coding: utf-8 -*-

import wx

TASK_RANGE = 50

class Example(wx.Frame):

def __init__(self, *args, **kw):
super(Example, self).__init__(*args, **kw)

self.InitUI()

def InitUI(self):

self.timer = wx.Timer(self, 1)
self.count = 0

self.Bind(wx.EVT_TIMER, self.OnTimer, self.timer)

pnl = wx.Panel(self)
vbox = wx.BoxSizer(wx.VERTICAL)
hbox1 = wx.BoxSizer(wx.HORIZONTAL)
hbox2 = wx.BoxSizer(wx.HORIZONTAL)
hbox3 = wx.BoxSizer(wx.HORIZONTAL)

self.gauge = wx.Gauge(pnl, range=TASK_RANGE, size=(250, 25))
self.btn1 = wx.Button(pnl, wx.ID_OK)
self.btn2 = wx.Button(pnl, wx.ID_STOP)
self.text = wx.StaticText(pnl, label='Task to be done')

self.Bind(wx.EVT_BUTTON, self.OnOk, self.btn1)
self.Bind(wx.EVT_BUTTON, self.OnStop, self.btn2)

hbox1.Add(self.gauge, proportion=1, flag=wx.ALIGN_CENTRE)
hbox2.Add(self.btn1, proportion=1, flag=wx.RIGHT, border=10)
hbox2.Add(self.btn2, proportion=1)
hbox3.Add(self.text, proportion=1)
vbox.Add((0, 30))
vbox.Add(hbox1, flag=wx.ALIGN_CENTRE)
vbox.Add((0, 20))
vbox.Add(hbox2, proportion=1, flag=wx.ALIGN_CENTRE)
vbox.Add(hbox3, proportion=1, flag=wx.ALIGN_CENTRE)

pnl.SetSizer(vbox)

self.SetSize((300, 200))
self.SetTitle('wx.Gauge')
self.Centre()
self.Show(True)

def OnOk(self, e):

if self.count >= TASK_RANGE:
return

self.timer.Start(100)
self.text.SetLabel('Task in Progress')

def OnStop(self, e):

if self.count == 0 or self.count >= TASK_RANGE or not self.timer.IsRunning():
return

self.timer.Stop()
self.text.SetLabel('Task Interrupted')

def OnTimer(self, e):

self.count = self.count + 1
self.gauge.SetValue(self.count)

if self.count == TASK_RANGE:

self.timer.Stop()
self.text.SetLabel('Task Completed')

def main():

ex = wx.App()
Example(None)
ex.MainLoop()

if __name__ == '__main__':
main()

我们创建了一个 进度条(gauge)和两个按钮。一个按钮开始走进度条,一个按钮停止走进度条。

1
2
self.timer = wx.Timer(self, 1)
self.count = 0

我们使用了 wx.Timer 来在特定的时间区间来执行代码,我们将在定义好的时间来更新进度条。 count 变量用来决定目前任务已经完成的比例。

1
self.gauge = wx.Gauge(pnl, range=TASK_RANGE, size=(250, 25))

上面是 wx.Gauge 部件的构造函数, range 参数定义了该部件最大的整数区间。

1
2
3
4
5
6
7
def OnOk(self, e):

if self.count >= TASK_RANGE:
return

self.timer.Start(100)
self.text.SetLabel('Task in Progress')

当我们点击 OK 按钮时,OnOK() 方法将被调用。首先我们检查 count 变量是否还在任务的整数区间内。如果不在,我们直接返回。如果还在,表明任务还在继续,我们开始 timer 定时器并更新静态文本。

1
2
3
4
5
6
7
def OnStop(self, e):

if self.count == 0 or self.count >= TASK_RANGE or not self.timer.IsRunning():
return

self.timer.Stop()
self.text.SetLabel('Task Interrupted')

当我们点击 Stop 按钮时,OnStop() 函数将被调用。我们检查了各种条件,符合的话我们停止定时器并更新静态文本。

1
2
3
4
5
6
7
8
9
def OnTimer(self, e):

self.count = self.count + 1
self.gauge.SetValue(self.count)

if self.count == TASK_RANGE:

self.timer.Stop()
self.text.SetLabel('Task Completed')

OnTimer() 方法在 timer 开始后被周期调用。在该方法内,我们更新 count 参数和进度条部件。如果 count 等于 TASK_RANGE,我们停止 timer 并更新静态文本。
wx.Gauge

wx.Slider

wx.Slider 部件有一个简单的操作柄,可以向前或向后滑动。我们可以使用它完成特定的任务。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#!/usr/bin/python
# -*- coding: utf-8 -*-

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)

sld = wx.Slider(pnl, value=200, minValue=150, maxValue=500, pos=(20, 20),
size=(250, -1), style=wx.SL_HORIZONTAL)

sld.Bind(wx.EVT_SCROLL, self.OnSliderScroll)

self.txt = wx.StaticText(pnl, label='200', pos=(20, 90))

self.SetSize((290, 200))
self.SetTitle('wx.Slider')
self.Centre()
self.Show(True)

def OnSliderScroll(self, e):

obj = e.GetEventObject()
val = obj.GetValue()

self.txt.SetLabel(str(val))


def main():

ex = wx.App()
Example(None)
ex.MainLoop()

if __name__ == '__main__':
main()

在 slider 中选择的值将被显示在下面的静态文本中。

1
sld = wx.Slider(pnl, value=200, minValue=150, maxValue=500, pos=(20, 20), size=(250, -1), style=wx.SL_HORIZONTAL)

上面的代码创建了 wx.Slider。在构造函数中,我们提供了它的初始位置,以及最大、最小的滑动位置,还有设定了它的水平方向。

1
sld.Bind(wx.EVT_SCROLL, self.OnSliderScroll)

当 wx.EVT_SCROLL 时间被触发的时候,将调用 OnSliderScroll() 函数。

1
self.txt = wx.StaticText(pnl, label='200', pos=(20, 90))

当前 slider 的值将被显示在下方的静态文本中。

1
2
3
4
5
6
def OnSliderScroll(self, e):

obj = e.GetEventObject()
val = obj.GetValue()

self.txt.SetLabel(str(val))

在 OnSliderScroll() 方法中,我们得到了事件的发送者并得到其当前被选择的值,然后将其设置到静态文本中。
wx.Slider

wx.SpinCtrl

wx.SpinCtrl 可以让我们对一个值进行增加或减少,它有两个按钮,一个带向上箭头,一个带向下箭头。用户可以直接输入数值,也可以通过两个箭头来对数值进行上下增减。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#!/usr/bin/python
# -*- coding: utf-8 -*-

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)


wx.StaticText(self, label='Convert Fahrenheit temperature to Celsius',
pos=(20,20))
wx.StaticText(self, label='Fahrenheit: ', pos=(20, 80))
wx.StaticText(self, label='Celsius: ', pos=(20, 150))

self.celsius = wx.StaticText(self, label='', pos=(150, 150))
self.sc = wx.SpinCtrl(self, value='0', pos=(150, 75), size=(60, -1))
self.sc.SetRange(-459, 1000)

btn = wx.Button(self, label='Compute', pos=(70, 230))
btn.SetFocus()
cbtn = wx.Button(self, label='Close', pos=(185, 230))

btn.Bind(wx.EVT_BUTTON, self.OnCompute)
cbtn.Bind(wx.EVT_BUTTON, self.OnClose)

self.SetSize((350, 310))
self.SetTitle('wx.SpinCtrl')
self.Centre()
self.Show(True)

def OnClose(self, e):

self.Close(True)

def OnCompute(self, e):

fahr = self.sc.GetValue()
cels = round((fahr - 32) * 5 / 9.0, 2)
self.celsius.SetLabel(str(cels))

def main():

ex = wx.App()
Example(None)
ex.MainLoop()

if __name__ == '__main__':
main()

上面的脚本将华氏温度转变为摄氏度。我们使用 wx.SpinCtrl 部件供用户来选择华氏温度的值。

1
2
self.sc = wx.SpinCtrl(self, value='0', pos=(150, 75), size=(60, -1))
self.sc.SetRange(-459, 1000)

在上面代码中,我们创建了一个初始值为 0 的 wx.SpinCtrl 部件,并通过 SetRange() 方法设置了该部件的取值范围。

1
2
3
4
5
def OnCompute(self, e):

fahr = self.sc.GetValue()
cels = round((fahr - 32) * 5 / 9.0, 2)
self.celsius.SetLabel(str(cels))

当我们点击 compute 按钮时,将会调用 OnCompute() 函数。在该函数中,我们获取用户设定的华氏温度值,并计算对应的摄氏温度值,将其更新在静态文本上。
wx.SpinCtrl
在本节中,我们主要讲解了各种核心 wxPython 部件。