wxpython图形用户界面编程
一、wxpython的基础
1.1 wxpython的基础
作为图形用户界面开发工具包 wxPython,主要提供了如下 GUI 内容:
- 窗口。
- 控件。
- 事件处理。
- 布局管理。
1.2 wxpython的类层次机构
1.3 wxpython的安装
- Windows 和 macOS 平台安装:
pip install -U wxPython
其中 install 是按照软件包,-U 是将指定软件包升级到最新版本。
- Linux 平台下使用 pip 安装有点麻烦,例如在 Ubuntu 16.04 安装,打开终端输入
如下指令:
pip install -U \
-f https://extras.wxpython.org/wxPython4/extras/linux/gtk3/ubuntu-16.04 \
wxPython
- 下载 wxPython 帮助文档和案例。
https://extras.wxpython.org/wxPython4/extras
1.4 第一个wxPython程序
import wx
# 创建应用程序对象
app = wx.App()
# 创建窗口对象
### size 是窗口的长和宽
### pos 使主窗口再电脑桌面显示的位置
### self.Center() 使窗口在电脑桌面显示居中位置,替代pos
frm = wx.Frame(None, title="第一个GUI程序!", size=(400, 300), pos=(100, 100))
frm.Show() # 显示窗口
app.MainLoop() # 进入主事件循环
1.5 窗口类MyFrame
# 自定义窗口类MyFrame
class MyFrame(wx.Frame):
def __init__(self):
super().__init__(parent=None, title="第一个GUI程序!", size=(400, 300), pos=(100, 100))
# TODO
class App(wx.App):
def OnInit(self):
# 创建窗口对象
frame = MyFrame()
frame.Show()
return True
def OnExit(self):
print('应用程序退出')
return 0
if __name__ == '__main__':
app = App()
app.MainLoop() # 进入主事件循环
1.6 使用面板(panel )
class MyFrame(wx.Frame):
def __init__(self):
super().__init__(parent=None, title="第一个GUI程序!", size=(600, 400), pos=(600, 200))
# 使用面板,面板指向父类MyFrame,也就是self
panel = wx.Panel(parent=self)
# 在面板上设置文本内容
statictext = wx.StaticText(parent=panel, label='Hello World!', pos=(10, 10))
class App(wx.App):
def OnInit(self):
# 创建窗口对象
frame = MyFrame()
frame.Show()
return True
def OnExit(self):
print('应用程序退出')
return 0
if __name__ == '__main__':
app = App()
app.MainLoop() # 进入主事件循环
Frame的内容面板图解结构,如下图
1.7 wxpython界面构建层次机构
注意:并不是指wxpython功能模块的类相关的继承层次机构
二、事件处理
在事件处理的过程中涉及4个要素:
- 事件。它是用户对界面的操作,在wxPython中事件被封装成为事件类wx.Event及其子类,例如按钮事件类是wx.CommandEvent,鼠标事件类是wx.Move Event。
- 事件类型。事件类型给出了事件的更多信息,它是一个整数。例如标事件wx.Move Event还可以有鼠标的右键按下(WX.EVT LEFT DOWN)和释放(wx.EVT左上)等。
- 事件源。它是事件发生的场所,就是各个控件,例如按钮事件的事件源是按钮。
- 事件处理者。 它是在wx.EvtHandler子类(事件处理类)中定义的一个方法。
绑定是通过事件处理类的 Bind()方法实现,Bind()方法语法如下:
Bind(self, event, handler,source=None, id=wx.ID_ANY, id2=Wx.ID_ANY)
- 其中参数event是事件类型,注意不是事件;
- handler是事件处理者,它对应到事件处理类中特定方法;
- source 是事件源;
- id是事件源的标识,可以省略source参数通过id绑定事件源:
- id2设置要绑定事件源id范围,当有多个事件源帮定到同一个事件处理者时可以使用此参数。
2.1 一对一事件处理
class MyFrame(wx.Frame):
def __init__(self):
super().__init__(parent=None, title="一对一事件处理", size=(600, 400))
self.Center() # 使主窗口在电脑桌面显示居中位置, pos可以不使用
# 使用面板,面板指向父类MyFrame,也就是self
panel = wx.Panel(parent=self)
# 在面板上设置文本内容
self.statictext = wx.StaticText(parent=panel, pos=(10, 10))
button = wx.Button(parent=panel, label='OK', pos=(100, 80))
# event是事件类型 handler是事件处理者,具体的自定义的执行方法 source是事件源,指定事件源的变量名字,也可以用id去指定事件源范围
self.Bind(event=wx.EVT_BUTTON, handler=self.on_click, source=button)
def on_click(self, event):
print(event)
self.statictext.SetLabelText('Hello Word')
class App(wx.App):
def OnInit(self):
# 创建窗口对象
frame = MyFrame()
frame.Show()
return True
def OnExit(self):
print('应用程序退出')
return 0
if __name__ == '__main__':
app = App()
app.MainLoop() # 进入主事件循环
代码执行效果图
2.2 一对多事件处理
多个事件源调用同一个方法进行处理
class MyFrame(wx.Frame):
def __init__(self):
super().__init__(parent=None, title="一对一事件处理", size=(600, 400))
self.Center() # 使主窗口在电脑桌面显示居中位置, pos可以不使用
# 使用面板,面板指向父类MyFrame,也就是self
panel = wx.Panel(parent=self)
# 在面板上设置文本内容
self.statictext = wx.StaticText(parent=panel, pos=(10, 10))
# 定义两个事件源,分别是button10, button11
button10 = wx.Button(parent=panel, id=10, label='button10', pos=(100, 80))
button11 = wx.Button(parent=panel, id=11, label='button11', pos=(140, 110))
# Bind是绑定不同类型的事件源去执行方法,这里的事件类型是button按钮
# event是事件类型 handler是事件处理者,具体的执行方法
# id是事件源起始id, id2是事件源的结束id,这是id范围是10到11,也就是说10到11的id事件源都会执行self.on_click方法
self.Bind(event=wx.EVT_BUTTON, handler=self.on_click, id=10, id2=11)
def on_click(self, event):
# 获取事件源的id
source_id = event.GetId()
# 根据事件源id执行不同的结果
if source_id == 10:
self.statictext.SetLabelText('button10')
else:
self.statictext.SetLabelText('button11')
class App(wx.App):
def OnInit(self):
# 创建窗口对象
frame = MyFrame()
frame.Show()
return True
def OnExit(self):
print('应用程序退出')
return 0
if __name__ == '__main__':
app = App()
app
三、布局管理
使用绝对布局会有如下问题:
- 子窗口(或控件)位置和大小不会随着父窗口的变化而变化。
- 在不同平台上显示效果可能差别很大。
- 在不同分辨率下显示效果可能差别很大。
- 字体的变化也会对显示效果有影响。
- 动态添加或删除子窗口(或控件)界面布局需要重新设计。
wxPython 提供了8个布局管理器类,如图19-10所示,包括:
wx.Sizer、wx.BoxSizer、wx.StaticBoxSizer , wx.WrapSizer, wx.StdDialogButtonSizer, wx.GridSizer 、 wx.FlexGridSizer和 wx.GridBagSizer .
3.1 Box 布局器
创建 wx.BoxSizer 对象时可以指定布局方向:
hbox = wx.BoxSizer(wx.HORIZONTAL) # 设置为水平方向布局
hbox = wx.BoxSizer() # 也是设置为水平方向布局,wx.HORIZONTAL是默认值可以省略
vhbox = wx.BoxSizer(wx.VERTICAL) # 设置为垂直方向布局
当需要添加子窗口(或控件)到父窗口时,需要调用 wx.BoxSizer 对象 Add()方法,
Add()方法是从父类 wx.Sizer 继承而来的,Add()方法语法说明如下:
Add(window, proportion=0, flag=0, border=0, userData=None) # 添加到父窗口
Add(sizer, proportion=0, flag=0, border=0, userData=None) # 添加到另外一个Sizer中,用于嵌套
Add(width, height, proportion=0, flag=0, border=0, userData=None) # 添加一个空白空间
注意: proportion=0 表示该组件不会随着窗口大小改变而改变大小
注意: proportion=1 表示该组件会随着窗口大小改变而改变大小
注意: 如果有多个组件都设置了proportion>0,则按比例分配空间
class MyFrame(wx.Frame):
def __init__(self):
super().__init__(parent=None, title="Box布局", size=(600, 400))
self.Center() # 使主窗口在电脑桌面显示居中位置, pos可以不使用
# 使用面板,面板指向父类MyFrame,也就是self
panel = wx.Panel(parent=self)
# 创建垂直方向box布局管理wx.VERTICAL
vbox = wx.BoxSizer(wx.VERTICAL)
# 设置静态文本模板,放在panel面板中
self.statictext = wx.StaticText(parent=panel, label='Button1单机')
# #添加静态文本到vbox布局管理器中,指定文本框在整个面板中所占权重为2,标志为固定大小填充,顶部有边框,水平居中,边框宽度为10
vbox.Add(self.statictext, proportion=2, flag=wx.FIXED_MINSIZE | wx.TOP | wx.CENTER, border=10)
button10 = wx.Button(parent=panel, id=10, label='button10')
button11 = wx.Button(parent=panel, id=11, label='button11')
self.Bind(event=wx.EVT_BUTTON, handler=self.on_click, id=10, id2=20)
# 创建水平方向box布局管理器
hbox = wx.BoxSizer(wx.HORIZONTAL)
hbox.Add(button10, proportion=0, flag=wx.EXPAND | wx.BOTTOM | wx.RIGHT, border=70)
hbox.Add(button11, proportion=0, flag=wx.EXPAND | wx.BOTTOM, border=70)
# 将水平box添加到垂直box
vbox.Add(hbox, proportion=1, flag=wx.CENTER)
# 设置面板的布局管理器vbox
panel.SetSizer(vbox)
'''将两个button放到一个水平方向布局管理器,然后将水平方向布局管理器放到垂直方向布局管理器中
添加控件到其父容器是通过parent属性,这里button和statictext的父容器都是面板,与布局管理器的添加是没有关系的
布局管理器添加是通过Add()方法添加,这个添加只是说将某个控件纳入布局管理器管理
不是添加到容器中,注意布局管理器不是一个容器'''
def on_click(self, event):
# 获取事件源的id
source_id = event.GetId()
# 根据事件源id执行不同的结果
if source_id == 10:
print('button10')
else:
print('button11')
class App(wx.App):
def OnInit(self):
# 创建窗口对象
frame = MyFrame()
frame.Show()
return True
def OnExit(self):
print('应用程序退出')
return 0
if __name__ == '__main__':
app = App()
app.MainLoop() # 进入主事件循环
运行效果:
3.2 StaticBox布局
wx.StaticBoxSizer构造方法如下:
-
1.wx.StaticBoxSizer(box,orient=HORIZONTAL)
box参数:wx.StaticBox(静态框)对象
orient参数:布局方向 -
2.wx.StaticBox(orient,parent,label=“”)
orient参数:布局方向
parent参数:设置所在的父窗口
label参数:设置边框的静态文本
class MyFrame(wx.Frame):
def __init__(self):
super().__init__(parent=None, title="StaticBox布局", size=(300, 200))
self.Center() # 使主窗口在电脑桌面显示居中位置, pos可以不使用
# 使用面板,面板指向父类MyFrame,也就是self
panel = wx.Panel(parent=self)
# 创建垂直方向box布局管理wx.VERTICAL
vbox = wx.BoxSizer(wx.VERTICAL)
# 设置静态文本模板,放在panel面板中
self.statictext = wx.StaticText(parent=panel, label='Button1单机')
# 添加静态文本到vbox布局管理器中
vbox.Add(self.statictext, proportion=2, flag=wx.FIXED_MINSIZE | wx.TOP | wx.CENTER, border=50)
button10 = wx.Button(parent=panel, id=10, label='button10')
button11 = wx.Button(parent=panel, id=11, label='button11')
self.Bind(event=wx.EVT_BUTTON, handler=self.on_click, id=10, id2=20)
# 创建静态框
sb = wx.StaticBox(parent=panel, label='静态按钮框')
# 创建水平方向box布局管理器,并加入sb静态框
hsbox = wx.StaticBoxSizer(sb, wx.HORIZONTAL)
hsbox.Add(button10, proportion=0, flag=wx.EXPAND | wx.BOTTOM, border=50)
hsbox.Add(button11, proportion=0, flag=wx.EXPAND | wx.BOTTOM, border=50)
# 将水平box添加到垂直box
vbox.Add(hsbox, proportion=1, flag=wx.CENTER)
# 设置面板的布局管理器vbox
panel.SetSizer(vbox)
def on_click(self, event):
# 获取事件源的id
source_id = event.GetId()
# 根据事件源id执行不同的结果
if source_id == 10:
print('button10')
else:
print('button11')
class App(wx.App):
def OnInit(self):
# 创建窗口对象
frame = MyFrame()
frame.Show()
return True
def OnExit(self):
print('应用程序退出')
return 0
if __name__ == '__main__':
app = App()
app.MainLoop() # 进入主事件循环
运行效果:
3.3 Grid 布局
Grid布局类wx.GridSizer,Grid布局以网格形式对子窗口(或控件)进行摆放,容器被分成大小相等的矩形,一个矩形中放置一个子窗口(或控件)。
wx.GridSizer的构造方法如下:
(1)wx.GridSizer(rows,cols,vgap,hgap)
创建指定行数和列数的wx.GridSizer对象,并指定水平和垂直间隙,参数hgap为水平间隙,参数vgap为垂直间隙,整数类型。添加的子窗口(或控件)个数超过rows*cols之积,则引发异常。
(2)wx.GridSizer(rows,cols,gap)
同wx.GridSizer(rows,cols,vgap,hgap),gap参数指定垂直间隙和水平间隙,gap参数是wx.Size类型
例如wx.Size(2,3)是设置水平间隙为2像素,垂直间隙为3像素
(3)wx.GridSizer(cols,vgap,hgap)
创建指定列数的wx.GridSizer对象,并指定水平和垂直间隙。由于没有限定行数,所以添加的子窗口(或控件)个数没有限制
(4)wx.GridSizer(cols,gap=wx.Size(0,0))
同wx.GridSizer(cols,vgap,hgap),gap参数是垂直间隙和水平间隙是wx.Size类型
class MyFrame(wx.Frame):
def __init__(self):
super().__init__(parent=None, title="Grid布局器", size=(400, 300))
# 使主窗口在电脑桌面显示居中位置, pos可以不使用
self.Center()
# 创建一个面板,名字叫panel,面板指向父类MyFrame,也就是self
panel = wx.Panel(parent=self)
# 创建9个按钮,3*3的布局
button1 = wx.Button(parent=panel, id=1, label='1')
button2 = wx.Button(parent=panel, id=2, label='2')
button3 = wx.Button(parent=panel, id=3, label='3')
button4 = wx.Button(parent=panel, id=4, label='4')
button5 = wx.Button(parent=panel, id=5, label='5')
button6 = wx.Button(parent=panel, id=6, label='6')
button7 = wx.Button(parent=panel, id=7, label='7')
button8 = wx.Button(parent=panel, id=8, label='8')
button9 = wx.Button(parent=panel, id=9, label='9')
# 将类型为按钮,上述9个按钮绑定到事件处理方法(handler)
self.Bind(event=wx.EVT_BUTTON, handler=self.on_click, id=1, id2=10)
#创建Grid布局管理器
gridsizer = wx.GridSizer(cols=3, rows=3, gap=wx.Size(5, 10))
# 将按钮添加进grid布局管理器中,最多添加9个控件,只能少不能多
gridsizer.AddMany(
[
(button1, 0, wx.EXPAND),
(button2, 0, wx.EXPAND),
(button3, 0, wx.EXPAND),
(button4, 0, wx.EXPAND),
(button5, 0, wx.EXPAND),
(button6, 0, wx.EXPAND),
(button7, 0, wx.EXPAND),
(button8, 0, wx.EXPAND),
(button9, 0, wx.EXPAND),
]
)
# 将Grid布局管理器添加到当前panel面板中
panel.SetSizer(gridsizer)
def on_click(self, event):
# 获取事件源的id
source_id = event.GetId()
# 根据事件源id执行不同的结果
if source_id == 10:
print('button10')
else:
print('button11')
class App(wx.App):
def OnInit(self):
# 创建窗口对象
frame = MyFrame()
frame.Show()
return True
def OnExit(self):
print('应用程序退出')
return 0
if __name__ == '__main__':
app = App()
app.MainLoop() # 进入主事件循环
运行效果:
3.4 FlexGrid布局
Grid布局时网格大小是固定的,如果想网格大小不同的界面可以使用FlexGrid布局。
FlexGrid是更加灵活的Grid布局。FlexGrid布局类是wx.FlexGridSizer,它的父类是wx.GridSizer。
wx.FlexGridSizer有两个特殊的方法:
(1)AddGrowableRow(idx,proportion=0)
指定行是可以扩展的,参数idx是行索引,从零开始;参数proportion是设置该行所占空间比例
(2)AddGrowableCo(idx,proportion=0)
指定列是可以扩展的,参数idx是列索引,从零开始;参数proportion是设置该列所占空间比例
class MyFrame(wx.Frame):
def __init__(self):
super().__init__(parent=None, title="FlexGrid布局", size=(400, 300))
self.Center() # 使主窗口在电脑桌面显示居中位置, pos可以不使用
# 使用面板,面板指向父类MyFrame,也就是self
panel = wx.Panel(parent=self)
# 创建FlexGrid布局管理器,3行2列,之间的空隙是10像素
fgs = wx.FlexGridSizer(3, 2, 10, 10)
# 静态文本(wx.StaticText)
title = wx.StaticText(panel, label='标题:')
author = wx.StaticText(panel, label='作者:')
review = wx.StaticText(panel, label='内容:')
# 文本框控件(wx.TextCtrl)
tcl = wx.TextCtrl(panel)
tc2 = wx.TextCtrl(panel)
tc3 = wx.TextCtrl(panel, style=wx.TE_MULTILINE)
fgs.AddMany([
title, (tcl, 1, wx.EXPAND),
author, (tc2, 1, wx.EXPAND),
review, (tc3, 1, wx.EXPAND)
])
# 指定行,(行索引,行所占空间比例)
fgs.AddGrowableRow(0, 1) # 高度占1/5
fgs.AddGrowableRow(1, 1) # 占1/5
fgs.AddGrowableRow(2, 3) # 占3/5
# 指定列,(列索引,列所占空间比例)
fgs.AddGrowableCol(0, 1)
fgs.AddGrowableCol(1, 2)
# 因FlexGrid管理器无法设置border边框,所以可以通过把FlexGrid管理器加入到Box管理器里面来
hbox = wx.BoxSizer(wx.HORIZONTAL)
hbox.Add(fgs, proportion=1, flag=wx.ALL | wx.EXPAND, border=15)
# 将Box布局管理器添加进面板
panel.SetSizer(hbox)
class App(wx.App):
def OnInit(self):
# 创建窗口对象
frame = MyFrame()
frame.Show()
return True
def OnExit(self):
print('应用程序退出')
return 0
if __name__ == '__main__':
app = App()
app.MainLoop() # 进入主事件循环
执行效果:
四、wxPython 控件
4.1 静态文本和按钮
wxPython 中静态文本类是 wx.StaticText,可以显示文本。wxPython 中的按钮主要有三个:wx.Button、wx.BitmapButton 和 wx.ToggleButton
- wx.Button 是普通按钮
- wx.BitmapButton 是带有图标按钮
- wx.ToggleButton 能进行两种状态切换的按钮。
class MyFrame(wx.Frame):
def __init__(self):
super().__init__(parent=None, title="静态文本和按钮", size=(400, 300))
self.Center() # 使主窗口在电脑桌面显示居中位置, pos可以不使用
# 使用面板,面板指向父类MyFrame,也就是self
panel = wx.Panel(parent=self)
# 创建垂直方向布局box
vbox = wx.BoxSizer(wx.VERTICAL)
# 创建一个静态文本,加入到panel面板,在面板中水平居中对齐
self.statictext = wx.StaticText(parent=panel, label="StaticText", style=wx.ALIGN_CENTER_HORIZONTAL)
# 创建一个普通的button,并绑定相应的方法(on_click)
button1 = wx.Button(parent=panel, id=1, label="Button")
self.Bind(event=wx.EVT_BUTTON, handler=self.on_click, source=button1)
# 创建一个ToggleButton,可以进行两种状态切换,并绑定相应的方法(on_click)
button2 = wx.ToggleButton(parent=panel, id=2, label="ToggleButton")
self.Bind(event=wx.EVT_BUTTON, handler=self.on_click, source=button2)
# 创建一个BitmapButton,带有图标按钮,并绑定相应的方法(on_click)
bmp = wx.Bitmap('icon/1.png', wx.BITMAP_TYPE_PNG)
button3 = wx.BitmapButton(parent=panel, id=3, bitmap=bmp)
self.Bind(event=wx.EVT_BUTTON, handler=self.on_click, source=button3)
# 添加到控件布局管理器中
vbox.Add(50, 50, proportion=1, flag=wx.CENTER | wx.FIXED_MINSIZE) # 面板添加空白行并居中
vbox.Add(self.statictext, proportion=1, flag=wx.CENTER | wx.EXPAND)
vbox.Add(button1, proportion=1, flag=wx.CENTER | wx.EXPAND)
vbox.Add(button2, proportion=1, flag=wx.CENTER | wx.EXPAND)
vbox.Add(button3, proportion=1, flag=wx.CENTER | wx.EXPAND)
panel.SetSizer(vbox)
def on_click(self, event):
self.statictext.SetLabelText("哈哈哈哈哈")
class App(wx.App):
def OnInit(self):
# 创建窗口对象
frame = MyFrame()
frame.Show()
return True
def OnExit(self):
print('应用程序退出')
return 0
if __name__ == '__main__':
app = App()
app.MainLoop() # 进入主事件循环
运行效果:
4.2 文本输入控件
文本输入控件类是 wx.TextCtrl,默认情况下只能文本输入控件中只能输入单行数据,如果想输入多行可以设置 style=wx.TE_MULTILINE。如果想把文本输入控件作为密码框使用,可以设置 style=wx.TE_PASSWORD。
class MyFrame(wx.Frame):
def __init__(self):
super().__init__(parent=None, title="文本输入框", size=(300, 200))
self.Center()
panel = wx.Panel(parent=self)
# 创建FlexGrid布局管理器
fgs = wx.FlexGridSizer(3, 2, 10, 10)
# 静态文本
user = wx.StaticText(parent=panel, label='用户:')
pwd = wx.StaticText(parent=panel, label='密码:')
content = wx.StaticText(parent=panel, label='多行文本:')
# 文本框控件,设置为类内部属性变量,可通过self调用
self.tc1 = wx.TextCtrl(parent=panel) # 将tc1改为实例变量
self.tc1.SetHint("请输入用户名") # 设置默认提示文字
self.tc2 = wx.TextCtrl(parent=panel, style=wx.TE_PASSWORD) # 将tc2改为实例变量
self.tc3 = wx.TextCtrl(parent=panel, style=wx.TE_MULTILINE) # 将tc3改为实例变量
# 添加保存按钮,当用户点击保存按钮时,可以在on_save方法中获取到数据
save_btn = wx.Button(parent=panel, label='保存')
self.Bind(event=wx.EVT_BUTTON, handler=self.on_save, source=save_btn) # 绑定点击事件
fgs.AddMany([
user, (self.tc1, 1, wx.EXPAND),
pwd, (self.tc2, 1, wx.EXPAND),
content, (self.tc3, 1, wx.EXPAND)
])
# 指定行,(行索引,行所占空间比例)
fgs.AddGrowableRow(0, 1) # 高度占1/5
fgs.AddGrowableRow(1, 1) # 占1/5
fgs.AddGrowableRow(2, 3) # 占3/5
# 指定列,(列索引,列所占空间比例)
fgs.AddGrowableCol(0, 1)
fgs.AddGrowableCol(1, 2)
# 创建了垂直布局(vbox)来容纳FlexGrid和保存按钮
vbox = wx.BoxSizer(wx.VERTICAL)
vbox.Add(fgs, proportion=1, flag=wx.ALL | wx.EXPAND, border=15)
vbox.Add(save_btn, proportion=0, flag=wx.ALIGN_CENTER | wx.BOTTOM, border=15)
panel.SetSizer(vbox)
def on_save(self, event):
# 获取三个文本框的内容,使用 GetValue() 获取各个文本框的内容
user_text = self.tc1.GetValue()
pwd_text = self.tc2.GetValue()
content_text = self.tc3.GetValue()
print('用户名:', user_text)
print('密码:', pwd_text)
print('内容:', content_text)
class App(wx.App):
def OnInit(self):
# 创建窗口对象
frame = MyFrame()
frame.Show()
return True
def OnExit(self):
print('应用程序退出')
return 0
if __name__ == '__main__':
app = App()
app.MainLoop() # 进入主事件循环
运行效果:
4.3 复选框和单选按钮
多选控件是复选框(wx.CheckBox)
单选控件是单选按钮(wx.RadioButton)
class MyFrame(wx.Frame):
def __init__(self):
super().__init__(parent=None, title="复选框和单选框", size=(400, 300))
self.Center()
panel = wx.Panel(parent=self)
# 创建水平方向布局box
hbox1 = wx.BoxSizer(wx.HORIZONTAL)
# 创建一个静态文本,加入到panel面板中
statictext = wx.StaticText(parent=panel, label="选择你喜欢的编程语言:")
# 创建3个CheckBox类型复选框
cb1 = wx.CheckBox(parent=panel, id=1, label='Python')
cb2 = wx.CheckBox(parent=panel, id=2, label='Java')
# cb2复选框设置为默认值
cb2.SetValue(True)
cb3 = wx.CheckBox(parent=panel, id=3, label='C++')
# 对事件进行绑定事件处理方法
self.Bind(event=wx.EVT_CHECKBOX, handler=self.checkbox, id=1, id2=3)
# 将静态文本和CheckBox事件加入到水平方向布局中
hbox1.Add(statictext, proportion=1, flag=wx.LEFT | wx.RIGHT | wx.FIXED_MINSIZE, border=5)
hbox1.Add(cb1, proportion=1, flag=wx.ALL | wx.FIXED_MINSIZE)
hbox1.Add(cb2, proportion=1, flag=wx.ALL | wx.FIXED_MINSIZE)
hbox1.Add(cb3, proportion=1, flag=wx.ALL | wx.FIXED_MINSIZE)
hbox2 = wx.BoxSizer(wx.HORIZONTAL)
statictext = wx.StaticText(parent=panel, label="选择性别: ")
# 创建RadioButton事件,wx.RB_GROUP指的是一个组,同一个RadioButton组后续不需要再加wx.RB_GROUP
radio1 = wx.RadioButton(parent=panel, id=4, label='男', style=wx.RB_GROUP)
radio2 = wx.RadioButton(parent=panel, id=5, label='女')
self.Bind(event=wx.EVT_RADIOBUTTON, handler=self.radiobutton, id=4, id2=5)
hbox2.Add(statictext, proportion=1, flag=wx.LEFT | wx.RIGHT | wx.FIXED_MINSIZE, border=5)
hbox2.Add(radio1, proportion=1, flag=wx.ALL | wx.FIXED_MINSIZE)
hbox2.Add(radio2, proportion=1, flag=wx.ALL | wx.FIXED_MINSIZE)
hbox3 = wx.BoxSizer(wx.HORIZONTAL)
statictext = wx.StaticText(parent=panel, label="选择你喜欢吃的水果: ")
radio3 = wx.RadioButton(parent=panel, id=6, label='橘子', style=wx.RB_GROUP)
radio4 = wx.RadioButton(parent=panel, id=7, label='苹果')
radio5 = wx.RadioButton(parent=panel, id=8, label='西瓜')
self.Bind(event=wx.EVT_RADIOBUTTON, handler=self.radiobutton, id=6, id2=8)
hbox3.Add(statictext, proportion=1, flag=wx.LEFT | wx.RIGHT | wx.FIXED_MINSIZE, border=5)
hbox3.Add(radio3, proportion=1, flag=wx.ALL | wx.FIXED_MINSIZE)
hbox3.Add(radio4, proportion=1, flag=wx.ALL | wx.FIXED_MINSIZE)
hbox3.Add(radio5, proportion=1, flag=wx.ALL | wx.FIXED_MINSIZE)
# 创建垂直布局管理器
vbox = wx.BoxSizer(wx.VERTICAL)
# 把3个水平的布局管理器加到垂直的布局管理器
vbox.Add(hbox1, proportion=0, flag=wx.ALL, border=5)
vbox.Add(hbox2, proportion=0, flag=wx.ALL, border=5)
vbox.Add(hbox3, proportion=0, flag=wx.ALL, border=5)
panel.SetSizer(vbox)
def checkbox(self, event):
cb = event.GetEventObject()
print(cb.GetLabel())
def radiobutton(self, event):
rb = event.GetEventObject()
print(rb.GetLabel())
class App(wx.App):
def OnInit(self):
# 创建窗口对象
frame = MyFrame()
frame.Show()
return True
def OnExit(self):
print('应用程序退出')
return 0
if __name__ == '__main__':
app = App()
app.MainLoop() # 进入主事件循环
运行效果:
4.4 下拉列表
wxPython 提供了两种下拉列表控件类:wx.ComboBox 和 wx.Choice,wx.ComboBox 默认它的文本框是可以修改的,wx.Choice 是只读不可以修改的,除此之外他们没有区别。
class MyFrame(wx.Frame):
def __init__(self):
super().__init__(parent=None, title="复选框和单选框", size=(400, 300))
self.Center()
panel = wx.Panel(parent=self)
# 创建水平方向布局box
hbox1 = wx.BoxSizer(wx.HORIZONTAL)
# 创建静态文本,放到panel面板中
statictext = wx.StaticText(parent=panel, label="选择你喜欢的编程语言:")
list1 = ["Python", "JavaScript", "C++", "JavaScript"]
# 创建可修改下拉列表文本框ComboBox
ch1 = wx.ComboBox(parent=panel, id=-1 , value='C', choices=list1, style=wx.CB_SORT)
self.Bind(event=wx.EVT_COMBOBOX, handler=self.combobox, source=ch1)
hbox1.Add(statictext, flag=wx.LEFT | wx.RIGHT | wx.FIXED_MINSIZE, border=5)
hbox1.Add(ch1, flag=wx.ALL | wx.FIXED_MINSIZE)
# 创建水平方向布局box
hbox2 = wx.BoxSizer(wx.HORIZONTAL)
# 创建静态文本,放到panel面板中
statictext = wx.StaticText(parent=panel, label="选择性别")
list2 = ['男', '女']
# 创建只读不可修改下拉列表文本框ComboBox
ch2 = wx.Choice(parent=panel, id=-1, choices=list2)
self.Bind(event=wx.EVT_CHOICE, handler=self.choice, source=ch2)
hbox2.Add(statictext, flag=wx.LEFT | wx.RIGHT | wx.FIXED_MINSIZE, border=5)
hbox2.Add(ch2, flag=wx.ALL | wx.FIXED_MINSIZE)
# 创建垂直布局管理器,将水平布局管理器加入进来
vbox = wx.BoxSizer(wx.VERTICAL)
vbox.Add(hbox1, proportion=0, flag=wx.ALL | wx.EXPAND, border=5)
vbox.Add(hbox2, proportion=0, flag=wx.ALL | wx.EXPAND, border=5)
panel.SetSizer(vbox)
def combobox(self, event):
print(f'combobox: {event.GetString()}')
def choice(self, event):
print(f'choice: {event.GetString()}')
class App(wx.App):
def OnInit(self):
# 创建窗口对象
frame = MyFrame()
frame.Show()
return True
def OnExit(self):
print('应用程序退出')
return 0
if __name__ == '__main__':
app = App()
app.MainLoop() # 进入主事件循环
执行效果:
4.5 列表
列表控件类似于下拉列表控件,只是没有文本框,只有一个列表选项,如图 19-20所示,列表控件可以单选或多选。列表控件类是 wx.ListBox。
wx.ListBox 参数style设置列表风格样式,常用的有4种风格:
- WX.LB_SINGLE。单选。
- wx.LB_MULTIPLE。多选。
- WX.LB_EXTENDED。也是多选,但需要按住Ctrl或Shit键时选择项目。
- Wx.LB_SORT。对列表选择项进行排序。
class MyFrame(wx.Frame):
def __init__(self):
super().__init__(parent=None, title="复选框和单选框", size=(400, 300))
self.Center()
panel = wx.Panel(parent=self)
# 创建水平方向布局box
hbox1 = wx.BoxSizer(wx.HORIZONTAL)
# 创建静态文本,放到panel面板中
statictext = wx.StaticText(parent=panel, label="选择你喜欢的编程语言:")
list1 = ["Python", "JavaScript", "C++", "JavaScript"]
# 创建可修改下拉列表,没有文本框, 单选(style=wx.LB_SINGLE)
lb1 = wx.ListBox(parent=panel, id=-1 , choices=list1, style=wx.LB_SINGLE)
self.Bind(event=wx.EVT_LISTBOX, handler=self.combobox, source=lb1)
hbox1.Add(statictext, flag=wx.LEFT | wx.RIGHT | wx.FIXED_MINSIZE, border=5)
hbox1.Add(lb1, proportion=1, flag=wx.ALL | wx.FIXED_MINSIZE)
# 创建水平方向布局box
hbox2 = wx.BoxSizer(wx.HORIZONTAL)
# 创建静态文本,放到panel面板中
statictext = wx.StaticText(parent=panel, label="选择你喜欢吃的水果:")
list2 = ['苹果', '橘子', '香蕉', '梨子']
# 创建可修改下拉列表,没有文本框, 多选(style=x.LB_MULTIPLE)
lb2 = wx.ListBox(parent=panel, id=-1, choices=list2, style=wx.LB_MULTIPLE)
self.Bind(event=wx.EVT_LISTBOX, handler=self.choice, source=lb2)
hbox2.Add(statictext, flag=wx.LEFT | wx.RIGHT | wx.FIXED_MINSIZE, border=5)
hbox2.Add(lb2, proportion=1, flag=wx.ALL | wx.FIXED_MINSIZE,)
# 创建垂直布局管理器,将水平布局管理器加入进来
vbox = wx.BoxSizer(wx.VERTICAL)
vbox.Add(hbox1, proportion=1, flag=wx.ALL | wx.EXPAND, border=5)
vbox.Add(hbox2, proportion=1, flag=wx.ALL | wx.EXPAND, border=5)
panel.SetSizer(vbox)
def combobox(self, event):
print(f'combobox: {event.GetString()}')
def choice(self, event):
print(f'choice: {event.GetString()}')
class App(wx.App):
def OnInit(self):
# 创建窗口对象
frame = MyFrame()
frame.Show()
return True
def OnExit(self):
print('应用程序退出')
return 0
if __name__ == '__main__':
app = App()
app.MainLoop() # 进入主事件循环
运行效果图:
4.6 静态图片控件
静态图片控件类是 wx.StaticBitmap。
class MyFrame(wx.Frame):
def __init__(self):
super().__init__(parent=None, title="复选框和单选框", size=(400, 300))
self.Center()
# 在父容器里面创建面板,名字为panel
panel = wx.Panel(parent=self)
self.bmps = [
# 创建Bitmap展示图片,图片类型为gif
wx.Bitmap('images/bird5.gif', wx.BITMAP_TYPE_GIF),
wx.Bitmap('images/bird4.gif', wx.BITMAP_TYPE_GIF),
wx.Bitmap('images/bird3.gif', wx.BITMAP_TYPE_GIF),
]
# 创建垂直布局管理器
vbox = wx.BoxSizer(wx.VERTICAL)
# 创建Button事件,在panel面板中显示button1按钮
button1 = wx.Button(parent=panel, id=1, label="button1")
button2 = wx.Button(parent=panel, id=2, label="button2")
self.Bind(event=wx.EVT_BUTTON, handler=self.on_click, id=1, id2=2)
# 创建静态bitmap事件,在panel面板中显示gif图片
self.image = wx.StaticBitmap(parent=panel, id=-1, bitmap=self.bmps[0])
vbox.Add(button1, proportion=1, flag=wx.CENTER | wx.EXPAND)
vbox.Add(button2, proportion=1, flag=wx.CENTER | wx.EXPAND)
vbox.Add(self.image, proportion=3, flag=wx.CENTER)
self.panel = panel
panel.SetSizer(vbox)
def on_click(self, event):
event_id = event.GetId()
if event_id == 1:
# 设置图片
self.image.SetBitmap(self.bmps[1])
else:
self.image.SetBitmap(self.bmps[2])
# 刷新panel面板,不刷新会影响图片显示效果
self.panel.Layout()
class App(wx.App):
def OnInit(self):
# 创建窗口对象
frame = MyFrame()
frame.Show()
return True
def OnExit(self):
print('应用程序退出')
return 0
if __name__ == '__main__':
app = App()
app.MainLoop() # 进入主事件循环
运行效果:
五、高级窗口
5.1 分割窗口
wx.SplitterWindow 中一个常用的方法有:
- SplitVertically(window1, window2, sashPosition=0)。设置左右布局的分隔窗口,window1 为左窗口,window2 为右窗口,sashPosition 是窗框的位置。
- SplitHorizontally(window1, window2, sashPosition=0)。设置上下布局的分隔窗口,window1 为上窗口,window2 为下窗口,sashPosition 是窗框的位置。
- SetMinimumPaneSize(paneSize)。设置最小窗口尺寸,如果是左右布局是指左窗口的最小尺寸,如果是上下布局是指上窗口的最小尺寸。如果没有设置则默认为 0。
class MyFrame(wx.Frame):
def __init__(self):
super().__init__(parent=None, title="分隔窗口", size=(400, 300))
self.Center()
# 在父窗口创建左右布局分割窗口,不要放到内容面板,直接放到freme
splitter = wx.SplitterWindow(self, -1)
# 创建左侧面板
leftPanel = wx.Panel(splitter)
# 创建右侧面板
rightPanel = wx.Panel(splitter)
# 设置哪个是左面板,哪个是右面板,窗框的位置是100
splitter.SplitVertically(leftPanel, rightPanel, 100)
# 设置面板最小的值
splitter.SetMinimumPaneSize(80)
list1 = ['apple', 'orange', 'pear']
# 创建列表控件,加入到左侧面板
lb2 = wx.ListBox(parent=leftPanel, id=-1, choices=list1, style=wx.LB_SINGLE)
# 为列表控件绑定事件
self.Bind(event=wx.EVT_LISTBOX, handler=self.on_click, source=lb2)
# 创建垂直布局管理器
vbox1 = wx.BoxSizer(wx.VERTICAL)
# 把lb2控件添加到垂直布局管理中
vbox1.Add(lb2, proportion=1, flag=wx.ALL | wx.EXPAND, border=5)
# 把vbox1设置到左侧面板
leftPanel.SetSizer(vbox1)
vbox2 = wx.BoxSizer(wx.VERTICAL)
self.content = wx.StaticText(rightPanel, label="右侧面板")
vbox2.Add(self.content, proportion=1, flag=wx.ALL | wx.EXPAND, border=5)
rightPanel.SetSizer(vbox2)
def on_click(self, event):
s = f'选择{event.GetString()}'
self.content.SetLabelText(s)
class App(wx.App):
def OnInit(self):
# 创建窗口对象
frame = MyFrame()
frame.Show()
return True
def OnExit(self):
print('应用程序退出')
return 0
if __name__ == '__main__':
app = App()
app.MainLoop() # 进入主事件循环
运行效果:
5.2 使用树
- AddRoot(text, image=-1, selImage=-1, data=None)。添加根节点,text 参数根节点显示的文本;image 参数是该节点未被选中时的图片索引,wx.TreeCtrl 中使用的图片被放到 wx.ImageList 图像列表中;selImage 参数是该节点被选中时的图片索引。data 参数是给节点传递的数据。方法返回节点,节点类型是 wx.TreeItemId。
- AppendItem(parent, text, image=-1, selImage=-1, data=None)。添加子节点,parent 参数是父节点,其他参数同 AddRoot()方法。方法返回值 wx.TreeItemId。
- SelectItem(item, select=True)。选中 item 节点,如图 19-24 所示 TreeRoot 节点被选
中。 - Expand(item)。展开 item 节点,如图 19-24 所示 Item 1 和 Item 4 节点处于展开状态。
- ExpandAll()。展开根节点下的所有子节点。
- ExpandAllChildren(item)。展开 item 节点下的所有子节点。
- AssignImageList(imageList)。保存 wx.ImageList 图像列表到树中,这样就可以在AddRoot()和 AppendItem()方法中使用图像列表索引了。
class MyFrame(wx.Frame):
def __init__(self):
super().__init__(parent=None, title="分隔窗口", size=(400, 300))
self.Center()
# 在父窗口创建左右布局分割窗口,不要放到内容面板,直接放到freme
splitter = wx.SplitterWindow(self, -1)
# 创建左侧面板
leftPanel = wx.Panel(splitter)
# 创建右侧面板
rightPanel = wx.Panel(splitter)
# 设置哪个是左面板,哪个是右面板,窗框的位置是100
splitter.SplitVertically(leftPanel, rightPanel, 200)
# 设置面板最小的值
splitter.SetMinimumPaneSize(80)
# 创建树控件
self.tree = self.CreateTreeCtrl(leftPanel)
# 为树控件绑定事件
self.Bind(event=wx.EVT_TREE_SEL_CHANGED, handler=self.on_click, source=self.tree)
# 创建垂直布局管理器
vbox1 = wx.BoxSizer(wx.VERTICAL)
# 把self.tree数控件添加到垂直布局管理中
vbox1.Add(self.tree, proportion=1, flag=wx.ALL | wx.EXPAND, border=5)
# 把vbox1设置到左侧面板
leftPanel.SetSizer(vbox1)
vbox2 = wx.BoxSizer(wx.VERTICAL)
self.content = wx.StaticText(rightPanel, label="右侧面板")
vbox2.Add(self.content, proportion=1, flag=wx.ALL | wx.EXPAND, border=5)
rightPanel.SetSizer(vbox2)
def CreateTreeCtrl(self, parent):
tree = wx.TreeCtrl(parent)
imglist = wx.ImageList(width=16, height=16, mask=True, initialCount=2)
imglist.Add(wx.ArtProvider.GetBitmap(wx.ART_FOLDER, size=wx.Size(16, 16)))
imglist.Add(wx.ArtProvider.GetBitmap(wx.ART_NORMAL_FILE, size=wx.Size(16, 16)))
tree.AssignImageList(imglist)
items = []
root = tree.AddRoot('TreeRoot', image=0)
items.append(tree.AppendItem(root, 'Item 1', 0))
items.append(tree.AppendItem(root, 'Item 2', 0))
items.append(tree.AppendItem(root, 'Item 3', 0))
items.append(tree.AppendItem(root, 'Item 4', 0))
items.append(tree.AppendItem(root, 'Item 5', 0))
for i in range(len(items)):
id = items[i]
tree.AppendItem(id, 'Subitem 1', 1)
tree.AppendItem(id, 'Subitem 2', 1)
tree.AppendItem(id, 'Subitem 3', 1)
tree.AppendItem(id, 'Subitem 4', 1)
tree.AppendItem(id, 'Subitem 5', 1)
tree.Expand(root)
tree.Expand(items[0])
tree.Expand(items[3])
tree.SelectItem(root)
return tree
def on_click(self, event):
item = event.GetItem()
self.content.SetLabel(self.tree.GetItemText(item))
class App(wx.App):
def OnInit(self):
# 创建窗口对象
frame = MyFrame()
frame.Show()
return True
def OnExit(self):
print('应用程序退出')
return 0
if __name__ == '__main__':
app = App()
app.MainLoop() # 进入主事件循环
运行效果:
六、使用菜单
6.1 使用菜单
菜单栏不添加到父窗口中,需要在顶级窗口中通过SetMenuBar(menuBar)方法将添加菜单栏。菜单栏(wx.MenuBar)通过 Append(menu,title)方法将菜单添加到菜单栏中,其中 menu 是菜单对象,title是菜单上文本。菜单对象(wx.Menu)通过 Append(menultem)方法将菜单项添加到菜单中。
kind是菜单项类型,菜单项类型主要有如下5种:
Wx.ITEM_SEPARATOR。分隔线菜单项:
Wx.ITEM_NORMAL。普通菜单项。
wx.ITEM_CHECK。复选框形式的菜单项,
WX.ITEM_RADIO。单选按钮形式的菜单项。
Wx.ITEM_DROPDOWN。下拉列表形式的菜单项。
class MyFrame(wx.Frame):
def __init__(self):
super().__init__(parent=None, title="使用菜单", size=(400, 300))
self.Center()
# 创建一个多行的文本控制器
self.text = wx.TextCtrl(self, id=-1, style=wx.EXPAND | wx.TE_MULTILINE)
# 创建一个垂直布局管理器
vbox = wx.BoxSizer(wx.VERTICAL)
# 将多行文本加到垂直布局管理
vbox.Add(self.text, proportion= 1, flag=wx.EXPAND | wx.ALL, border=1)
self.SetSizer(vbox)
# 创建一个菜单栏
memubar = wx.MenuBar()
# 创建一个菜单对象
file_menu = wx.Menu()
# 将菜单对象file_menu添加到菜单栏中,显示文本为【文件】
memubar.Append(file_menu,title='文件')
# 通过MenuItem新建一个菜单项,显示为【新建】,加入到file_menu【文件】菜单对象中
new_item = wx.MenuItem(parentMenu=file_menu, id=99, text='新建', kind=wx.ITEM_NORMAL)
# 将菜单项new_item【新建】添加到file_menu【文件】菜单对象中
file_menu.Append(new_item)
# 菜单对象间的分割线
file_menu.AppendSeparator()
# 新建一个【编辑】菜单对象
edit_menu = wx.Menu()
# 通过MenuItem新建一个菜单项,显示为【复制】,使用父菜单edit_menu【编辑】菜单对象中
copy_item = wx.MenuItem(parentMenu=edit_menu, id=100, text='复制', kind=wx.ITEM_NORMAL)
# 将菜单项copy_item添加到edit_menu菜单对象中
edit_menu.Append(copy_item)
# 通过MenuItem新建一个菜单项,显示为【剪切】,使用父菜单edit_menu【编辑】菜单对象中
cut_item = wx.MenuItem(parentMenu=edit_menu, id=101, text='剪切', kind=wx.ITEM_NORMAL)
# 将菜单项cut_item添加到edit_menu菜单对象中
edit_menu.Append(cut_item)
# 通过MenuItem新建一个菜单项,显示为【粘贴】,使用父菜单edit_menu【编辑】菜单对象中
paste_item = wx.MenuItem(parentMenu=edit_menu, id=102, text='粘贴', kind=wx.ITEM_NORMAL)
# 将菜单项paste_item添加到edit_menu菜单对象中
edit_menu.Append(paste_item)
# 以上菜单项事件绑定到事件处理方法self.on_click
self.Bind(event=wx.EVT_MENU, handler=self.on_click, id=99, id2=102)
# 将菜单项edit_item【编辑】添加到file_menu【文件】菜单对象中
file_menu.Append(id=99, item='编辑', subMenu=edit_menu)
# 将菜单栏添加到顶级窗口中
self.SetMenuBar(memubar)
def on_click(self, event):
event_id = event.GetId()
if event_id == 99:
self.text.SetLabel('单击【新建】菜单')
elif event_id == 100:
self.text.SetLabel('单击【复制】菜单')
elif event_id == 101:
self.text.SetLabel('单击【剪切】菜单')
else:
self.text.SetLabel('单击【粘贴】菜单')
class App(wx.App):
def OnInit(self):
# 创建窗口对象
frame = MyFrame()
frame.Show()
return True
def OnExit(self):
print('应用程序退出')
return 0
if __name__ == '__main__':
app = App()
app.MainLoop() # 进入主事件循环
使用效果:
七、使用工具栏
wxPython 中工具栏类是wx.Toolbar。顶级窗口都有一个 ToolBar 属性可以设置它的工具栏,然后通过工具栏的 AddTool()方法添加按钮到工具栏,最后调用工具栏的 Realize()确定。
import wx
import wx.grid
# 自定义窗口类MyFrame
class MyFrame(wx.Frame):
def __init__(self):
super().__init__(parent=None, title='使用工具栏', size=(550, 500))
self.Centre() # 设置窗口居中
self.Show(True)
self.text = wx.TextCtrl(self, -1, style=wx.EXPAND | wx.TE_MULTILINE)
vbox = wx.BoxSizer(wx.VERTICAL)
vbox.Add(self.text, proportion=1, flag=wx.EXPAND | wx.ALL, border=1)
self.SetSizer(vbox)
menubar = wx.MenuBar()
file_menu = wx.Menu()
new_item = wx.MenuItem(file_menu, wx.ID_NEW, text="新建", kind=wx.ITEM_NORMAL)
file_menu.Append(new_item)
file_menu.AppendSeparator()
edit_menu = wx.Menu()
copy_item = wx.MenuItem(edit_menu, 100, text="复制", kind=wx.ITEM_NORMAL)
edit_menu.Append(copy_item)
cut_item = wx.MenuItem(edit_menu, 101, text="剪切", kind=wx.ITEM_NORMAL)
edit_menu.Append(cut_item)
paste_item = wx.MenuItem(edit_menu, 102, text="粘贴", kind=wx.ITEM_NORMAL)
edit_menu.Append(paste_item)
file_menu.Append(wx.ID_ANY, "编辑", edit_menu)
menubar.Append(file_menu, '文件')
self.SetMenuBar(menubar)
tb = wx.ToolBar(self, wx.ID_ANY)
self.ToolBar = tb
tsize = (24, 24)
new_bmp = wx.ArtProvider.GetBitmap(wx.ART_NEW, wx.ART_TOOLBAR, tsize)
open_bmp = wx.ArtProvider.GetBitmap(wx.ART_FILE_OPEN, wx.ART_TOOLBAR, tsize)
copy_bmp = wx.ArtProvider.GetBitmap(wx.ART_COPY, wx.ART_TOOLBAR, tsize)
paste_bmp = wx.ArtProvider.GetBitmap(wx.ART_PASTE, wx.ART_TOOLBAR, tsize)
tb.AddTool(10, "New", new_bmp, kind=wx.ITEM_NORMAL, shortHelp="New")
tb.AddTool(20, "Open", open_bmp, kind=wx.ITEM_NORMAL, shortHelp="Open")
tb.AddSeparator()
tb.AddTool(30, "Copy", copy_bmp, kind=wx.ITEM_NORMAL, shortHelp="Copy")
tb.AddTool(40, "Paste", paste_bmp, kind=wx.ITEM_NORMAL, shortHelp="Paste")
tb.AddSeparator()
tb.AddTool(201, "back", wx.Bitmap("menu_icon/back.png"), kind=wx.ITEM_NORMAL, shortHelp="Back")
tb.AddTool(202, "forward", wx.Bitmap("menu_icon/forward.png"), kind=wx.ITEM_NORMAL, shortHelp="Forward")
self.Bind(wx.EVT_MENU, self.on_click, id=201, id2=202)
tb.AddSeparator()
tb.Realize()
def on_click(self, event):
event_id = event.GetId()
if event_id == 201:
self.text.SetLabel('单击【Back】按钮')
else:
self.text.SetLabel('单击【Forward】按钮')
class App(wx.App):
def OnInit(self):
# 创建窗口对象
frame = MyFrame()
frame.Show()
return True
if __name__ == '__main__':
app = App()
app.MainLoop() # 进入主事件循环
使用效果: