wxpython图形用户界面编程

wxpython图形用户界面编程

一、wxpython的基础

1.1 wxpython的基础

作为图形用户界面开发工具包 wxPython,主要提供了如下 GUI 内容:

  1. 窗口。
  2. 控件。
  3. 事件处理。
  4. 布局管理。

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,也就是selfpanel = 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 Truedef OnExit(self):print('应用程序退出')return 0if __name__ == '__main__':app = App()app.MainLoop()  # 进入主事件循环

Frame的内容面板图解结构,如下图
在这里插入图片描述

1.7 wxpython界面构建层次机构

注意:并不是指wxpython功能模块的类相关的继承层次机构

在这里插入图片描述

二、事件处理

在事件处理的过程中涉及4个要素:

  1. 事件。它是用户对界面的操作,在wxPython中事件被封装成为事件类wx.Event及其子类,例如按钮事件类是wx.CommandEvent,鼠标事件类是wx.Move Event。
  2. 事件类型。事件类型给出了事件的更多信息,它是一个整数。例如标事件wx.Move Event还可以有鼠标的右键按下(WX.EVT LEFT DOWN)和释放(wx.EVT左上)等。
  3. 事件源。它是事件发生的场所,就是各个控件,例如按钮事件的事件源是按钮。
  4. 事件处理者。 它是在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,也就是selfpanel = 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 Truedef OnExit(self):print('应用程序退出')return 0if __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,也就是selfpanel = wx.Panel(parent=self)# 在面板上设置文本内容self.statictext = wx.StaticText(parent=panel, pos=(10, 10))# 定义两个事件源,分别是button10, button11button10 = 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):# 获取事件源的idsource_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 Truedef OnExit(self):print('应用程序退出')return 0if __name__ == '__main__':app = App()app

三、布局管理

使用绝对布局会有如下问题:

  1. 子窗口(或控件)位置和大小不会随着父窗口的变化而变化。
  2. 在不同平台上显示效果可能差别很大。
  3. 在不同分辨率下显示效果可能差别很大。
  4. 字体的变化也会对显示效果有影响。
  5. 动态添加或删除子窗口(或控件)界面布局需要重新设计。
    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,也就是selfpanel = wx.Panel(parent=self)# 创建垂直方向box布局管理wx.VERTICALvbox = wx.BoxSizer(wx.VERTICAL)# 设置静态文本模板,放在panel面板中self.statictext = wx.StaticText(parent=panel, label='Button1单机')# #添加静态文本到vbox布局管理器中,指定文本框在整个面板中所占权重为2,标志为固定大小填充,顶部有边框,水平居中,边框宽度为10vbox.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添加到垂直boxvbox.Add(hbox, proportion=1, flag=wx.CENTER)# 设置面板的布局管理器vboxpanel.SetSizer(vbox)'''将两个button放到一个水平方向布局管理器,然后将水平方向布局管理器放到垂直方向布局管理器中 添加控件到其父容器是通过parent属性,这里button和statictext的父容器都是面板,与布局管理器的添加是没有关系的布局管理器添加是通过Add()方法添加,这个添加只是说将某个控件纳入布局管理器管理不是添加到容器中,注意布局管理器不是一个容器'''def on_click(self, event):# 获取事件源的idsource_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 Truedef OnExit(self):print('应用程序退出')return 0if __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,也就是selfpanel = wx.Panel(parent=self)# 创建垂直方向box布局管理wx.VERTICALvbox = 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添加到垂直boxvbox.Add(hsbox, proportion=1, flag=wx.CENTER)# 设置面板的布局管理器vboxpanel.SetSizer(vbox)def on_click(self, event):# 获取事件源的idsource_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 Truedef OnExit(self):print('应用程序退出')return 0if __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,也就是selfpanel = 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):# 获取事件源的idsource_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 Truedef OnExit(self):print('应用程序退出')return 0if __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,也就是selfpanel = 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/5fgs.AddGrowableRow(1, 1)  # 占1/5fgs.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 Truedef OnExit(self):print('应用程序退出')return 0if __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,也就是selfpanel = wx.Panel(parent=self)# 创建垂直方向布局boxvbox = 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 Truedef OnExit(self):print('应用程序退出')return 0if __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/5fgs.AddGrowableRow(1, 1)  # 占1/5fgs.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 Truedef OnExit(self):print('应用程序退出')return 0if __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)# 创建水平方向布局boxhbox1 = 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_GROUPradio1 = 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 Truedef OnExit(self):print('应用程序退出')return 0if __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)# 创建水平方向布局boxhbox1 = wx.BoxSizer(wx.HORIZONTAL)# 创建静态文本,放到panel面板中statictext = wx.StaticText(parent=panel, label="选择你喜欢的编程语言:")list1 = ["Python", "JavaScript", "C++", "JavaScript"]# 创建可修改下拉列表文本框ComboBoxch1 = 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)# 创建水平方向布局boxhbox2 = wx.BoxSizer(wx.HORIZONTAL)# 创建静态文本,放到panel面板中statictext = wx.StaticText(parent=panel, label="选择性别")list2 = ['男', '女']# 创建只读不可修改下拉列表文本框ComboBoxch2 = 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 Truedef OnExit(self):print('应用程序退出')return 0if __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)# 创建水平方向布局boxhbox1 = 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)# 创建水平方向布局boxhbox2 = 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 Truedef OnExit(self):print('应用程序退出')return 0if __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()# 在父容器里面创建面板,名字为panelpanel = wx.Panel(parent=self)self.bmps = [# 创建Bitmap展示图片,图片类型为gifwx.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 = panelpanel.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 Truedef OnExit(self):print('应用程序退出')return 0if __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()# 在父窗口创建左右布局分割窗口,不要放到内容面板,直接放到fremesplitter =  wx.SplitterWindow(self, -1)# 创建左侧面板leftPanel = wx.Panel(splitter)# 创建右侧面板rightPanel = wx.Panel(splitter)# 设置哪个是左面板,哪个是右面板,窗框的位置是100splitter.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 Truedef OnExit(self):print('应用程序退出')return 0if __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()# 在父窗口创建左右布局分割窗口,不要放到内容面板,直接放到fremesplitter =  wx.SplitterWindow(self, -1)# 创建左侧面板leftPanel = wx.Panel(splitter)# 创建右侧面板rightPanel = wx.Panel(splitter)# 设置哪个是左面板,哪个是右面板,窗框的位置是100splitter.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 treedef 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 Truedef OnExit(self):print('应用程序退出')return 0if __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_clickself.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 Truedef OnExit(self):print('应用程序退出')return 0if __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 = tbtsize = (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 Trueif __name__ == '__main__':app = App()app.MainLoop()  # 进入主事件循环

使用效果:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/63215.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

水仙花数(流程图,NS流程图)

题目:打印出所有的100-999之间的"水仙花数",并画出流程图和NS流程图。所谓"水仙花数"是指一个三位数,其各位数字立方和等于该数本身。例如:153是一个"水仙花数",因为1531的三次方&#…

不配置python环境,直接用PyCharm就可以?

有的伙伴可能遇到不安装python环境只安装pycharm也可以进行运行代码。 所以自认为是不需要解释器就可以运行? 这个是不现实的,有很多伙伴可能是安装了Pycharm,但Pycharm看你电脑上没有解释器,所以在安装的时候给你默认安装在C盘…

前端面试汇总(不定时更新)

目录 HTML & CSS1. XML、HTML、XHTML 有什么区别?⭐2. XML和JSON的区别?3. 是否了解W3C的规范?⭐4. 什么是语义化标签?⭐⭐5. 行内元素和块级元素的区别?⭐6. 行内元素和块级元素的转换?⭐7. 常用的块级…

SpringCloud微服务实战系列:03spring-cloud-gateway业务网关灰度发布

目录 spring-cloud-gateway 和zuul spring webflux 和 spring mvc spring-cloud-gateway 的两种模式 spring-cloud-gateway server 模式下配置说明 grayLb://system-server 灰度发布代码实现 spring-cloud-gateway 和zuul zuul 是spring全家桶的第一代网关组件&#x…

ActiveMQ 反序列化漏洞CVE-2015-5254复现

文章目录 一、产生原因二、利用条件三、利用过程四、PoC(概念验证)五、poc环境验证使用find搜索vulhub已安装目录打开activeMQ组件查看配置文件端口启动镜像-文件配置好后对于Docker 镜像下载问题及解决办法设置好镜像源地址,进行重启docker查…

vue3监听横向滚动条的位置;鼠标滚轮滑动控制滚动条滚动;监听滚动条到顶端

1.横向取值scrollLeft 竖向取值scrollTop 2.可以监听到最左最右侧 3.鼠标滚轮滑动控制滚动条滚动 效果 <template><div><div class"scrollable" ref"scrollableRef"><!-- 内容 --><div style"width: 2000px; height: 100…

WPF xaml 文件详解

<div id"content_views" class"htmledit_views"><h2><a name"t0"></a>1.总述</h2> 创建好了WPF项目后&#xff0c;最重要的是对 App和MainWindow的理解&#xff0c;在一开始的时候&#xff0c;极容易就直接在Main…

鸿蒙开发-ArkTS 创建自定义组件

在 ArkTS 中创建自定义组件是一个相对简单但功能强大的过程。以下是如何在 ArkTS 中创建和使用自定义组件的详细步骤&#xff1a; 一、定义自定义组件 使用Component注解&#xff1a;为了注册一个组件&#xff0c;使其能够在其他文件中被引用&#xff0c;你需要使用Component…

水表的数字表盘分割数据集labelme格式3023张13类别

数据集格式&#xff1a;labelme格式(不包含mask文件&#xff0c;仅仅包含jpg图片和对应的json文件) 图片数量(jpg文件个数)&#xff1a;3023 标注数量(json文件个数)&#xff1a;3023 标注类别数&#xff1a;13 标注类别名称:["readbox_1","center",&q…

跟着AI 学 AI, 开发一个ChatBot, 集成 Json 数据和查询

按照规律&#xff0c;使用AI生成一个架构图 直接上代码&#xff0c;为了方便学习&#xff0c;直接按照如下方式&#xff0c;复制到你的开发环境即可调试&#xff0c;运行代码。做学习参考。 代码注释多次说明这里&#xff0c;不在赘述。 "type": "carousel&qu…

使用枚举实现单例模式,不会反序列化破坏攻击,不会被反射破坏攻击。(附带枚举单例的简单实现)

原因分析 1.反序列化方法 ① jdk8中的Enum源码中对反序列化方法进行重写&#xff0c;抛出异常。 java.lang.Enum#readObject方法截图如下 ②java.io.ObjectInputStream#readObject 方法中的 readEnum 方法处理了枚举类型的反序列化&#xff0c;从而确保了枚举的单例特性。 …

MongoDB-副本集

一、什么是 MongoDB 副本集&#xff1f; 1.副本集的定义 MongoDB 的副本集&#xff08;Replica Set&#xff09;是一组 MongoDB 服务器实例&#xff0c;它们存储同一数据集的副本&#xff0c;确保数据的高可用性和可靠性。副本集中的每个节点都有相同的数据副本&#xff0c;但…

《数据结构》(408代码题)

2009 单链表&#xff08;双指针&#xff09; 分析&#xff1a;首先呢&#xff0c;给我们的数据结构是一个带有表头结点的单链表&#xff0c;也不允许我们改变链表的结构。链表的长度不是直接给出的啊&#xff0c;所以这个倒数也很棘手。那我们该如何解决这个“k”呢&#xff0c…

6.1 初探MapReduce

MapReduce是一种分布式计算框架&#xff0c;用于处理大规模数据集。其核心思想是“分而治之”&#xff0c;通过Map阶段将任务分解为多个简单任务并行处理&#xff0c;然后在Reduce阶段汇总结果。MapReduce编程模型包括Map和Reduce两个阶段&#xff0c;数据来源和结果存储通常在…

Cad c#.net 一键修改标注dimension中的文本内容

本例为给标注加前缀&#xff0c;也可定制其他形式&#xff0c;效果如下&#xff1a; public class Demo{[CommandMethod("xx")]//public void Dim(){Document doc Application.DocumentManager.MdiActiveDocument;Database db doc.Database;Editor ed doc.Editor;…

旅游系统旅游小程序PHP+Uniapp

旅游门票预订系统&#xff0c;支持景点门票、导游产品便捷预订、美食打卡、景点分享、旅游笔记分享等综合系统 更新日志 V1.3.0 1、修复富文本标签 2、新增景点入驻【高级版本】3、新增门票核销【高级版】4、新增门票端口【高级版】

MacOS系统 快速安装appium 步骤详解

在macOS系统上&#xff0c;你可以通过使用nvm&#xff08;Node Version Manager&#xff09;来管理Node.js的版本&#xff0c;并基于nvm安装的Node.js环境来快捷地安装Appium。以下是具体步骤&#xff1a; 一、安装nvm 下载nvm 访问nvm的GitHub仓库&#xff08;nvm GitHub&…

技术速递|.NET 9 简介

作者&#xff1a;.NET 团队 排版&#xff1a;Alan Wang 今天&#xff0c;我们非常激动地宣布 .NET 9的发布&#xff0c;这是迄今为止最高效、最现代、最安全、最智能、性能最高的 .NET 版本。这是来自世界各地数千名开发人员又一年努力的成果。这个新版本包括数千项性能、安全和…

Vue项目打包部署到服务器

1. Vue项目打包部署到服务器 1.1. 配置 &#xff08;1&#xff09;修改package.json文件同级目录下的vue.config.js文件。 // vue.config.js module.exports {publicPath: ./, }&#xff08;2&#xff09;检查router下的index.js文件下配置的mode模式。   检查如果模式改…

NPU是什么?电脑NPU和CPU、GPU区别介绍

随着人工智能技术的飞速发展&#xff0c;计算机硬件架构也在不断演进以适应日益复杂的AI应用场景。其中&#xff0c;NPU&#xff08;Neural Processing Unit&#xff0c;神经网络处理器&#xff09;作为一种专为深度学习和神经网络运算设计的新型处理器&#xff0c;正逐渐崭露头…