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,也就是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个要素:

  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,也就是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

三、布局管理

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

  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,也就是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()  # 进入主事件循环

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【优选算法篇】位运算小课堂:从入门到精通的奇妙之旅(上篇)

文章目录 须知 💬 欢迎讨论:如果你在学习过程中有任何问题或想法,欢迎在评论区留言,我们一起交流学习。你的支持是我继续创作的动力! 👍 点赞、收藏与分享:觉得这篇文章对你有帮助吗&#xff1…

pytest入门九:feature

fixture是pytest特有的功能,用以在测试执行前和执行后进行必要的准备和清理工作。使用pytest.fixture标识,定义在函数前面。在你编写测试函数的时候,你可以将此函数名称做为传入参数,pytest将会以依赖注入方式,将该函数…

Day9 神经网络的偏导数基础

多变量函数与神经网络 在神经网络中,我们经常遇到多变量函数。这些函数通常描述了网络的输入、权重、偏置与输出之间的关系。例如,一个简单的神经元输出可以表示为: z f ( w 1 x 1 w 2 x 2 … w n x n b ) z f(w_1x_1 w_2x_2 \ldots…

sg-exam:Star 2.2k,一套完善的在线教育平台,支持在线考试、在线学习,教育项目用它就没有错~~

​嗨,大家好,我是小华同学,关注我们获得“最新、最全、最优质”开源项目和高效工作学习方法 sg-exam是一个基于Java语言的在线考试系统,它集成了试卷管理、试题管理、考试安排、在线作答、自动阅卷等功能。该项目旨在帮助教育机构…

ArkTS中string和String/number和Number类型大小写的区别

ArkTS和TypeScript类似,string 和 String,number 和 Number 之间有一些重要的区别: 基本类型与对象类型 基本类型 (string, number): string 和 number 是基本数据类型,用于表示原始值。例如:let str: str…

Ubuntu22.04切换gcc版本教程

在编译安装程序的时候,由于gcc版本过高,导致编译无法通过,需要降低gcc版本。 一、安装gcc版本 根据自己的需求安装gcc版本。 sudo apt update sudo apt install gcc-10 g++-10二、切换gcc版本 sudo update-alternatives --install /usr/bin/gcc gcc

c++领域展开第四幕——类和对象(上篇收尾 this指针、c++和c语言的初步对比)超详细!!!!

文章目录 前言一、this指针二、c和c语言的初步对比总结 前言 上篇我们初步学习了类的基本概念以及实例化 今天我们来学习类的构造以及析构还有类的默认成员函数,类和对象这一部分都会有点难 跟着我一起来吧 一、this指针 Date类中有 Init 与 Print 两个成员函数&…

python | linux | ModuleNotFoundError: No module named ‘WFlib‘ |找不到模块

问题&#xff1a; (base) beautyby521-7:~/Website-Fingerprinting-Library-master$ bash scripts/NetCLR.sh Traceback (most recent call last):File "/home/beauty/Website-Fingerprinting-Library-master/exp/pretrain.py", line 8, in <module>from WFli…

联发科MTK8788_MT8788安卓核心板安兔兔跑分_安卓主板方案商

MT8788安卓核心板具有集成的蓝牙、fm、WLAN和gps模块&#xff0c;是一个高度集成的基带平台&#xff0c;包括调制解调器和应用处理子系统&#xff0c;启用LTE/LTE-A和C2K智能设备应用程序。该芯片集成了工作在2.0GHz的ARM Cortex-A73、最高可达2.0GHz的ARM Cortex-A53和功能强大…

云计算HCIP-OpenStack02

书接上回&#xff1a; 云计算HCIP-OpenStack01-CSDN博客 7.OpenStack核心服务 7.1Horizon&#xff1a;界面管理服务 Horizon提供了OpenStack中基于web界面的管理控制页面&#xff0c;用户或者是管理员都需要通过该服务进行OpenStack的访问和控制 界面管理服务需要依赖于keyston…

ElasticSearch的自动补全功能(拼音分词器、自定义分词器、DSL实现自动补全查询、RestAPI实现自动补全查询)

文章目录 1. 什么是自动补全2. 拼音分词器2.1 初识拼音分词器2.2 下载拼音分词器2.3 安装拼音分词器2.4 测试拼音分词器 3. 自定义分词器3.1 拼音分词器存在的问题3.2 分词器&#xff08;analyzer&#xff09;的组成3.3 如何自定义分词器3.4 拼音分词器的可选参数3.5 配置自定义…

AI一键分析小红书对标账号‼️

宝子们&#xff0c;AI小助手近期发现了一款宝藏AI工具&#xff0c;拥有对标账号AI分析功能&#xff0c;只需10秒就能全面掌握对标账号的运营情况&#xff0c;并且可以根据分析结果提供创作方向和灵感&#xff0c;轻松助力1:1复刻起号&#xff01; 功能亮点&#xff1a; &…

【5G】5G的主要架构选项

最初&#xff0c;在3GPP讨论中考虑了所有可能的聚合和核心网络组合&#xff0c;共有八个架构选项。以下重点介绍option2、3、4和7。 1. 独立组网 (Standalone, SA) 架构选项 2 &#xff1a;Standalone architecture with 5G-core 特点&#xff1a; 5G核心网&#xff08;5GC, …

数据分析实战—鸢尾花数据分类

1.实战内容 (1) 加载鸢尾花数据集(iris.txt)并存到iris_df中,使用seaborn.lmplot寻找class&#xff08;种类&#xff09;项中的异常值&#xff0c;其他异常值也同时处理 。 import pandas as pd from sklearn.datasets import load_iris pd.set_option(display.max_columns, N…

鸿蒙项目云捐助第十讲鸿蒙App应用分类页面二级联动功能实现

鸿蒙项目云捐助第十讲鸿蒙App应用分类页面二级联动功能实现 在之前的教程中完成了分类页面的左右两侧的列表结构&#xff0c;如下图所示。 接下来需要实现左侧分类导航项的点击操作&#xff0c;可以友好的提示用户选择了哪一个文字分类导航项。 一、左侧文字分类导航的处理 …

VSCode:Remote-SSH插件安装使用 -- 在VSCode中使用SSH

VSCode&#xff1a;Remote-SSH插件安装使用 1.安装Remote-SSH2.使用Remote-SSH 本文&#xff0c;将在Visual Studio Code中&#xff0c;安装Remote-SSH插件&#xff0c;实现SSH连接远程服务器。 1.安装Remote-SSH 打开VSCode&#xff0c;侧边栏中找到扩展模块(或CtrlShiftX快捷…

【机器人】Graspness 端到端 抓取点估计 | 论文解读

在复杂场景中实现抓取检测&#xff0c;Graspness是一种端到端的方法&#xff1b; 输入点云数据&#xff0c;输出抓取角度、抓取深度、夹具宽度等信息。 开源地址&#xff1a;GitHub - rhett-chen/graspness_implementation: My implementation of Graspnet Graspness. 论文地…

OpenWebUI,RAG+外部知识库+AI写文的开源应用

引言 自从去年AI火起来之后&#xff0c;很多人便热衷于寻找适合自用的AI开源项目&#xff0c;把各家大模型API接入到自己的AI程序里&#xff0c;便可以通过AI辅助完成一系列日常任务&#xff0c;比如内容翻译/润色/总结/撰写、格式转换、数据分类、代码分析、角色扮演等等。 …

力扣-图论-15【算法学习day.65】

前言 ###我做这类文章一个重要的目的还是给正在学习的大家提供方向和记录学习过程&#xff08;例如想要掌握基础用法&#xff0c;该刷哪些题&#xff1f;&#xff09;我的解析也不会做的非常详细&#xff0c;只会提供思路和一些关键点&#xff0c;力扣上的大佬们的题解质量是非…

单元测试知识总结

我们希望每段代码都是自测试的&#xff0c;每次改动之后&#xff0c;都能自动发现对现有功能的影响。 1 测试要求 在对软件单元进行动态测试之前&#xff0c;应对软件单元的源代码进行静态测试&#xff1b; 应建立测试软件单元的环境&#xff0c;如数据准备、桩模块、模拟器…