wxPython操作图形用户界面
1、wxPython 安装
1.1、Windows 和 macOS 平台安装:
pip install -U wxPython
其中 install 是按照软件包,-U 是将指定软件包升级到最新版本。
1.2、Linux 平台下使用 pip 安装有点麻烦,例如在 Ubuntu 16.04 安装,打开终端输入 如下指令:
pip install -U -f https://extras.wxpython.org/wxPython4/extras/linux/gtk3/ubuntu-16.04 wxPython
1.3、下载 wxPython 帮助文档和案例。
https://extras.wxpython.org/wxPython4/extras
1.4.官方文档
https://www.wxpython.org/
2、wxPython 基础.
作为图形用户界面开发工具包 wxPython,主要提供了如下 GUI 内容:
1. 窗口。
2. 控件。
3. 事件处理。
4. 布局管理。
2.1、wxPython 类层次结构
2.2、第一个 wxPython 程序
第一个程序
#!/usr/bin/env python # encoding: utf-8 """ @author: Irving Shi """ import wx app = wx.App() # 创建应用程序对象 # 创建窗口对象 title:标题 size: 窗口大小 pos: 窗口的位置 frm = wx.Frame(None, title='第一个gui程序', size=(400, 300), pos=(100, 100)) frm.Show() # 显示窗口 app.MainLoop() # 进入主事件循环
2.3、窗口类 MyFrame
import wx # 自定义窗口类MyFrame class MyFrame(wx.Frame): def __init__(self): super().__init__(parent=None, title="第一个GUI程序!", size=(400, 300), pos=(100, 100)) class App(wx.App): def OnInit(self): # 创建窗口对象 frame = MyFrame() frame.Show() return True def OnExit(self): print('应用程序退出') return 0
2.4、使用面板
import wx # 自定义窗口类MyFrame class MyFrame(wx.Frame): def __init__(self): super().__init__(parent=None, title="第一个GUI程序!", size=(400, 300)) self.Centre() # 设置窗口居中 ① 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 if __name__ == '__main__': app = App() app.MainLoop() # 进入主事件循环
3、事件处理
在事件处理的过程中涉及 4 个要素:
1. 事件。
2. 事件类型。
3. 事件源。
4. 事件处理者。
绑定是通过事件处理类的 Bind()方法实现,Bind()方法语法如下:
Bind(self, event, handler, source=None, id=wx.ID_ANY, id2=wx.ID_ANY)
3.1 一对一事件处理
#!/usr/bin/env python # encoding: utf-8 """ @author: Irving Shi """ import wx # 自定义窗口类MyFrame class MyFrame(wx.Frame): def __init__(self): super().__init__(parent=None, title="一对一事件处理", size=(300, 180)) self.Centre() # 设置窗口居中 ① panel = wx.Panel(parent=self) self.statictext = wx.StaticText(parent=panel, pos=(110, 20)) b = wx.Button(parent=panel, label='OK', pos=(100, 50)) self.Bind(wx.EVT_BUTTON, self.on_click, b) def on_click(self, event): # print(event) self.statictext.SetLabelText('hello world') class App(wx.App): def OnInit(self): # 创建窗口对象 frame = MyFrame() frame.Show() return True if __name__ == '__main__': app = App() app.MainLoop() # 进入主事件循环
3.2、一对多事件处理
#!/usr/bin/env python # encoding: utf-8 """ @author: Irving Shi """ import wx # 自定义窗口类MyFrame class MyFrame(wx.Frame): def __init__(self): super().__init__(parent=None, title="一对多事件处理", size=(300, 180)) self.Centre() # 设置窗口居中 ① panel = wx.Panel(parent=self) self.statictext = wx.StaticText(parent=panel, pos=(110, 15)) b1 = wx.Button(parent=panel, id=10, label='button1', pos=(100, 45)) b2 = wx.Button(parent=panel, id=11, label='button2', pos=(100, 85)) # self.Bind(wx.EVT_BUTTON, self.on_click, b1) # 一对一事件 # self.Bind(wx.EVT_BUTTON, self.on_click, b2) # 一对一事件 self.Bind(wx.EVT_BUTTON, self.on_click, id=10, id2=20, ) # 一对多事件 def on_click(self, event): print(event.GetId()) button_id = event.GetId() if button_id == 10: self.statictext.SetLabelText('hello world button 1') else: self.statictext.SetLabelText('hello world button 2') class App(wx.App): def OnInit(self): # 创建窗口对象 frame = MyFrame() frame.Show() return True if __name__ == '__main__': app = App() app.MainLoop() # 进入主事件循环
3.3、鼠标事件处理
#!/usr/bin/env python # -*- coding:utf-8 -*- # @Author: Irving Shi import wx # 自定义窗口类MyFrame class MyFrame(wx.Frame): def __init__(self): super().__init__(parent=None, title="鼠标事件处理", size=(400, 300)) self.Centre() # 设置窗口居中 ① # panel = wx.Panel(parent=self) # self.statictext = wx.StaticText(parent=panel, pos=(110, 15)) self.Bind(wx.EVT_LEFT_DOWN, self.on_left_down) self.Bind(wx.EVT_LEFT_UP, self.on_left_up) self.Bind(wx.EVT_MOTION, self.on_mouse_move) def on_left_down(self, evt): print('鼠标按下') def on_left_up(self, evt): print('鼠标释放') def on_mouse_move(self, event): """鼠标移动事件""" # 鼠标移动 # 鼠标按下左键 if event.Dragging() and event.LeftIsDown(): # 获取鼠标移动的坐标 pos = event.GetPosition() print(pos) class App(wx.App): def OnInit(self): # 创建窗口对象 frame = MyFrame() frame.Show() return True if __name__ == '__main__': app = App() app.MainLoop() # 进入主事件循环
4、布局管理
使用绝对布局会有如下问题:
-
子窗口(或控件)位置和大小不会随着父窗口的变化而变化。
-
在不同平台上显示效果可能差别很大。
-
在不同分辨率下显示效果可能差别很大。
-
字体的变化也会对显示效果有影响。
-
动态添加或删除子窗口(或控件)界面布局需要重新设计。
4.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参数仅被wx.BoxSizer使用,设置当前子窗口(或控件)在父窗口所占空间比例: flag 参数标志,用来控制对齐、边框和调整尺寸: border 参数包含边框的宽度: userData 参数可被用来传递额外的数据
4.1.1对齐 flag 标志
wx.ALIGN_TOP # 顶对齐 wx.ALIGN_BOTTOM # 底对齐 wx.ALIGN_LEFT # 左对齐 wx.ALIGN_RIGHT # 右对齐 wx.ALIGN_CENTER # 居中对齐 wx.ALIGN_CENTER_VERTICAL # 垂直居中对齐 wx.ALIGN_CENTER_HORIZONTAL水 # 平居中对齐 wx.ALIGN_CENTRE # 同 wx.ALIGN_CENTER wx.ALIGN_CENTRE_VERTICAL # 同 wx.ALIGN_CENTER_VERTICAL wx.ALIGN_CENTRE_HORIZONTAL # 同 wx.ALIGN_CENTER_HORIZONTAL
4.1.2、边框 flag 标志
wx.TOP # 设置有顶部边框,边框的宽度需要通过 Add()方法的 border 参数设置 wx.BOTTOM # 设置有底部边框 wx.LEFT # 设置有左边框 wx.RIGHT # 设置有右边框 wx.ALL # 设置 4 面全有边框
4.1.3、调整尺寸 flag 标志
wx.EXPAND # 调整子窗口(或控件)完全填满有效空间 wx.SHAPED # 调整子窗口(或控件)填充有效空间,但保存高宽比 wx.FIXED_MINSIZE # 调整子窗口(或控件)为最小尺寸 wx.RESERVE_SPACE_EVEN_IF_ HIDDEN # 设置此标志后,子窗口(或控件)如果被隐藏,所占空间保留
4.1.4、示例
#!/usr/bin/env python # -*- coding:utf-8 -*- # @Author: Irving Shi import wx # 自定义窗口类MyFrame class MyFrame(wx.Frame): def __init__(self): super().__init__(parent=None, title="box布局", size=(300, 120)) self.Centre() # 设置窗口居中 ① panel = wx.Panel(parent=self) # 创建垂直方向box布局管理器 vbox = wx.BoxSizer(wx.VERTICAL) # 创建静态文本 self.statictext = wx.StaticText(parent=panel, label="button1单机") # 添加静态文本到box布局管理器 vbox.Add(self.statictext, proportion=2, flag=wx.FIXED_MINSIZE | wx.TOP | wx.CENTER, border=5) button1 = wx.Button(parent=panel, id=10, label="button1") button2 = wx.Button(parent=panel, id=11, label="button2") self.Bind(wx.EVT_BUTTON, self.on_click, id=10, id2=20) # 创建水平方向box布局管理器 hbox = wx.BoxSizer(wx.HORIZONTAL) # wx.BoxSizer() hbox.Add(button1, proportion=0, flag=wx.BOTTOM | wx.EXPAND, border=5) hbox.Add(button2, proportion=0, flag=wx.BOTTOM | wx.EXPAND, border=5) # 把水平box添加到垂直box vbox.Add(hbox, proportion=2, flag=wx.CENTER | wx.BOTTOM, border=5) # 把垂直box添加到面板 panel.SetSizer(vbox) def on_click(self, event): print(event.GetId()) class App(wx.App): def OnInit(self): # 创建窗口对象 frame = MyFrame() frame.Show() return True if __name__ == '__main__': app = App() app.MainLoop() # 进入主事件循环
4.2、StaticBox 布局
4.2.1 wx.StaticBoxSizer 构造方法如下:
wx.StaticBoxSizer(box, orient=HORIZONTAL) #box 参数是 wx.StaticBox(静态框)对象,orient 参数是布局方向。 wx.StaticBoxSizer(orient, parent, label="") # orient 参数是布局方向,parent 参数是设置所在父窗口,label 参数设置边框的静态文本。
4.2.2、 示例
#!/usr/bin/env python # -*- coding:utf-8 -*- # @Author: Irving Shi import wx # 自定义窗口类MyFrame class MyFrame(wx.Frame): def __init__(self): super().__init__(parent=None, title="StaticBox布局", size=(300, 120)) self.Centre() # 设置窗口居中 ① panel = wx.Panel(parent=self) # 创建垂直方向box布局管理器 vbox = wx.BoxSizer(wx.VERTICAL) # 创建静态文本 self.statictext = wx.StaticText(parent=panel, label="button1单机") # 添加静态文本到box布局管理器 vbox.Add(self.statictext, proportion=2, flag=wx.FIXED_MINSIZE | wx.TOP | wx.CENTER, border=5) button1 = wx.Button(parent=panel, id=10, label="button1") button2 = wx.Button(parent=panel, id=11, label="button2") self.Bind(wx.EVT_BUTTON, self.on_click, id=10, id2=20) # 创建静态box s_box = wx.StaticBox(parent=panel, label="静态框") # 创建水平方向静态box布局管理器 hsbox = wx.StaticBoxSizer(s_box, orient=wx.HORIZONTAL) # wx.BoxSizer() hsbox.Add(button1, proportion=0, flag=wx.BOTTOM | wx.EXPAND, border=5) hsbox.Add(button2, proportion=0, flag=wx.BOTTOM | wx.EXPAND, border=5) # 把水平静态box添加到垂直box vbox.Add(hsbox, proportion=2, flag=wx.CENTER | wx.BOTTOM, border=5) # 把垂直box添加到面板 panel.SetSizer(vbox) def on_click(self, event): print(event.GetId()) class App(wx.App): def OnInit(self): # 创建窗口对象 frame = MyFrame() frame.Show() return True if __name__ == '__main__': app = App() app.MainLoop() # 进入主事件循环