wxPython
- Python中的图形用户界面开发库
- Tkinter是Python官方提供的图形用户界面开发库, 用于封装Tk GUI工具包.
- PyQt是非Python官方提供的图形用户界面开发库, 用于封装Qt工具包.
- wxPython是非Python官方提供的图形用户界面开发库.
程序结构
若要构建一个wxPython程序, 至少需要一个应用对象和一个窗口对象.
import wx
# 创建应用程序对象
app = wx.App()
# 创建窗口对象, 第一个参数表示所在父窗口
frm = wx.Frame(parent=None, title="第一个程序", size=(400, 300), pos=(100, 100))
# 显示窗口
frm.Show()
# 应用程序进入主事件循环中
app.MainLoop()
自定义窗口类
import wx
# 自定义窗口类
class MyFrame(wx.Frame):
def __init__(self):
super().__init__(parent=None, title="第一个程序", size=(400, 300), pos=(100, 100))
# 你的代码...(控件)
# 创建面板对象
panel = wx.Panel(parent=self)
# 创建静态文本对象
statictext = wx.StaticText(parent=panel, label="Hello World! ", pos=(10, 10))
app = wx.App()
frm = MyFrame()
frm.Show()
app.MainLoop()
事件处理
-
事件: wxPython中的事件被封装为事件类
wx.Event
及其子类. 例如按钮事件类
wx.CommandEvent
, 鼠标事件类wx.MoveEvent
. -
事件源: 事件发生的场所, 就是各个控件.
-
事件处理程序: 一个响应用户事件的方法.
import wx # 自定义窗口类 class MyFrame(wx.Frame): def __init__(self): super().__init__(parent=None, title="事件处理", size=(300, 180)) panel = wx.Panel(parent=self) # 创建静态文本对象 self.statictext = wx.StaticText(parent=panel, label="请单击OK按钮", pos=(110, 20)) # 创建按钮对象 b = wx.Button(parent=panel, label="OK", pos=(100, 50)) # 绑定事件, wx.EVT_BUTTON是事件类型, 即按钮单击事件; self.on_click是事件处理程序; b是事件源, 即按钮对象 self.Bind(wx.EVT_BUTTON, self.on_click, b) # 定义事件处理程序 def on_click(self, event): # event:事件对象 self.statictext.SetLabelText("Hello, World! ") app = wx.App() frm = MyFrame() frm.Show() app.MainLoop()
布局管理
-
wx.BoxSizer
: 盒子布局管理器是最常用的布局管理器, 它可以让其中的子窗口(或控件)沿垂直或水平方向布局.-
创建盒子布局管理器对象, 默认水平方向布局:
wx.BoxSizer(wx.HORIZONTAL/wx.VERTICAL)
-
添加子窗口(或控件)到父窗口的方法:
Add(window, proportion=0, flag=0, border=0)
添加到另外一个布局对象, 用于布局嵌套:
Add(sizer, proportion=0, flag=0, border=0)
flag对齐标志 说明 wx.ALIGN_TOP 顶对齐 wx.ALIGN_BUTTOM 底对齐 wx.ALIGN_LEFT 左对齐 wx.ALIGN_RIGHT 右对齐 wx.ALIGN_CENTER (CENTRE) 居中对齐 wx.ALIGN_CENTER_VERTICAL 垂直居中对齐 wx.ALIGN_CENTER_HORIZONTAL 水平居中对齐 flag边框标志 说明 wx.TOP 设置有顶部边框, 边框的宽度通过Add()方法的border参数设置 wx.BOTTOM 设置有底部边框 wx.LEFT 设置有左边框 wx.RIGHT 设置有右边框 wx.ALL 设置4面有边框 flag调整尺寸标志 说明 wx.EXPAND 调整子窗口(或控件)完全填满有效空间 wx.SHAPED 调整子窗口(或控件)填充有效空间, 但保存高宽比 wx.FIXED_MINSIZE 调整子窗口(或控件)为最小尺寸 wx.RESERVE_SPACE_EVEN_IF_HIDDEN 设置此标志后, 子窗口(或控件)如果被隐藏, 则所占空间保留 import wx class MyFrame(wx.Frame): def __init__(self): super().__init__(parent=None, title="事件处理", size=(300, 180)) panel = wx.Panel(parent=self) self.statictext = wx.StaticText(parent=panel, label="请单击OK按钮", pos=(110, 20)) b = wx.Button(parent=panel, label="OK", pos=(100, 50)) self.Bind(wx.EVT_BUTTON, self.on_click, b) # 创建垂直方向的盒子布局管理器对象 vbox = wx.BoxSizer(wx.VERTICAL) # 添加静态文本到vbox布局管理器 vbox.Add(self.statictext, proportion=1, flag=wx.ALIGN_CENTER | wx.TOP, border=30) # 添加按钮b到vbox布局管理器 vbox.Add(b, proportion=1, flag=wx.ALIGN_CENTER | wx.SHAPED | wx.BOTTOM, border=30) # 设置面板采用vbox布局管理器 panel.SetSizer(vbox) def on_click(self, event): self.statictext.SetLabelText("Hello, World! ") app = wx.App() frm = MyFrame() frm.Show() app.MainLoop()
-
-
盒子布局管理器嵌套示例
import wx class MyFrame(wx.Frame): def __init__(self): super(MyFrame, self).__init__(parent=None, title="来自主神的消息", size=(300, 120), pos=(500, 200)) panel = wx.Panel(parent=self) self.statictext = wx.StaticText(parent=panel, label="想明白生命的意义吗? ") b1 = wx.Button(parent=panel, id=10, label="确认") b2 = wx.Button(parent=panel, id=11, label="Yes") # 将id为10~20的控件绑定到按钮单击事件 self.Bind(wx.EVT_BUTTON, self.on_click, id=10, id2=20) # 创建包含两个按钮的盒子布局管理器对象 box1 = wx.BoxSizer(wx.HORIZONTAL) box1.Add(b1, proportion=1, flag=wx.EXPAND | wx.ALL, border=10) box1.Add(b2, proportion=1, flag=wx.EXPAND | wx.ALL, border=10) # 创建包含静态文本和box1的盒子布局管理器对象 box2 = wx.BoxSizer(wx.VERTICAL) box2.Add(self.statictext, proportion=1, flag=wx.ALIGN_CENTER | wx.TOP, border=10) box2.Add(box1, proportion=1, flag=wx.ALIGN_CENTER | wx.SHAPED) panel.SetSizer(box2) def on_click(self, event): event_id = event.GetId() if event_id == 10: self.statictext.SetLabelText("你是这次来的人里素质最好的一个. ") else: self.statictext.SetLabelText("Hello World! ") app = wx.App() frm = MyFrame() frm.Show() app.MainLoop()
控件
-
文本输入控件
- 普通文本
- 密码
- 多行文本
import wx class MyFrame(wx.Frame): def __init__(self): super(MyFrame, self).__init__(parent=None, title="文本输入", size=(300, 260), pos=(500, 200)) panel = wx.Panel(parent=self) tc1 = wx.TextCtrl(panel, style=0, value="Khru") # tc1.SetValue("Khru") print(tc1.GetValue()) tc2 = wx.TextCtrl(panel, style=wx.TE_PASSWORD) tc3 = wx.TextCtrl(panel, style=wx.TE_MULTILINE) userid = wx.StaticText(panel, label="用户ID: ") pwd = wx.StaticText(panel, label="密码: ") content = wx.StaticText(panel, label="多行文本: ") vbox = wx.BoxSizer(orient=wx.VERTICAL) vbox.Add(userid, flag=wx.EXPAND | wx.LEFT | wx.TOP, border=10) vbox.Add(tc1, flag=wx.FIXED_MINSIZE | wx.ALL, border=10) vbox.Add(pwd, flag=wx.EXPAND | wx.LEFT, border=10) vbox.Add(tc2, flag=wx.FIXED_MINSIZE | wx.ALL, border=10) vbox.Add(content, flag=wx.EXPAND | wx.LEFT, border=10) vbox.Add(tc3, flag=wx.EXPAND | wx.ALL, border=10) panel.SetSizer(vbox) app = wx.App() frm = MyFrame() frm.Show() app.MainLoop()
-
单选按钮和复选框控件
import wx class MyFrame(wx.Frame): def __init__(self): super().__init__(parent=None, title="单选按钮和复选框", size=(330, 120), pos=(500, 200)) panel = wx.Panel(parent=self) st1 = wx.StaticText(panel, label="您的性别: ") rb1 = wx.RadioButton(panel, id=1, label="男", style=wx.RB_GROUP) rb2 = wx.RadioButton(panel, id=2, label="女") # 在下一个wx.RB_GROUP之前的单选按钮都是一组的 self.Bind(wx.EVT_RADIOBUTTON, self.on_rb_click, id=1, id2=2) hbox1 = wx.BoxSizer() hbox1.Add(st1, flag=wx.LEFT | wx.RIGHT, border=5) hbox1.Add(rb1) hbox1.Add(rb2) st2 = wx.StaticText(panel, label="您喜欢的编程语言: ") cb1 = wx.CheckBox(panel, id=3, label="Python") cb2 = wx.CheckBox(panel, id=4, label="Java") cb3 = wx.CheckBox(panel, id=5, label="C++") cb1.SetValue(True) # 默认状态为未选中, True表示选中 self.Bind(wx.EVT_CHECKBOX, self.on_cb_click, id=3, id2=5) hbox2 = wx.BoxSizer() hbox2.Add(st2, flag=wx.LEFT | wx.RIGHT, border=5) hbox2.Add(cb1) hbox2.Add(cb2) hbox2.Add(cb3) vbox = wx.BoxSizer(orient=wx.VERTICAL) vbox.Add(hbox1, flag=wx.ALL, border=10) vbox.Add(hbox2, flag=wx.ALL, border=10) panel.SetSizer(vbox) # 事件处理程序将在每次事件源被选中或取消时调用 def on_rb_click(self, event): rb = event.GetEventObject() # 从事件对象中取出事件源对象 print("性别为{}".format(rb.GetLabel())) def on_cb_click(self, event): cb = event.GetEventObject() print("{0} is checked? {1}".format(cb.GetLabel(), event.IsChecked())) # print("{0} is checked? {1}".format(cb.GetLabel(), cb.Get3StateValue())) # Gets the state of a 3-state checkbox. app = wx.App() frm = MyFrame() frm.Show() app.MainLoop()
-
列表
import wx class MyFrame(wx.Frame): def __init__(self): super().__init__(parent=None, title="列表", size=(350, 175), pos=(500, 200)) panel = wx.Panel(parent=self) st1 = wx.StaticText(panel, label="选择你最喜欢的编程语言: ") lb1 = wx.ListBox(panel, choices=["Python", "Java", "C++"], style=wx.LB_SINGLE) self.Bind(event=wx.EVT_LISTBOX, handler=self.on_lb1, source=lb1) hbox1 = wx.BoxSizer() hbox1.Add(st1, proportion=1, flag=wx.LEFT | wx.RIGHT, border=5) hbox1.Add(lb1, proportion=1, flag=wx.SHAPED) st2 = wx.StaticText(panel, label="选择你喜欢的水果: ") lb2 = wx.ListBox(panel, choices=["苹果", "橘子", "香蕉"], style=wx.LB_EXTENDED) self.Bind(event=wx.EVT_LISTBOX, handler=self.on_lb2, source=lb2) hbox2 = wx.BoxSizer() hbox2.Add(st2, proportion=1, flag=wx.LEFT | wx.RIGHT, border=5) hbox2.Add(lb2, proportion=1, flag=wx.SHAPED) vbox = wx.BoxSizer(wx.VERTICAL) vbox.Add(hbox1, flag=wx.EXPAND | wx.ALL, border=5) vbox.Add(hbox2, flag=wx.EXPAND | wx.ALL, border=5) panel.SetSizer(vbox) def on_lb1(self, event): listbox = event.GetEventObject() print("最喜欢的编程语言是: {}".format(listbox.GetSelection())) def on_lb2(self, event): listbox = event.GetEventObject() print("喜欢的水果是: {}".format(listbox.GetSelections())) app = wx.App() frm = MyFrame() frm.Show() app.MainLoop()
-
静态图片控件
import wx class MyFrame(wx.Frame): def __init__(self): super().__init__(parent=None, title="静态图片控件", size=(500, 500), pos=(500, 200)) self.panel = wx.Panel(parent=self) # 这里面板是MyFrame类的实例变量 # 创建wx.Bitmap对象的列表 self.bmps = [wx.Bitmap(name="images/python.jpg", type=wx.BITMAP_TYPE_JPEG), wx.Bitmap(name="images/sin.gif", type=wx.BITMAP_TYPE_GIF), wx.Bitmap(name="images/ml.png", type=wx.BITMAP_TYPE_PNG)] # 创建静态图片控件对象, 显示的图片是self.bmps[0] self.sb = wx.StaticBitmap(self.panel, bitmap=self.bmps[0]) b1 = wx.Button(self.panel, id=1, label="Button1") b2 = wx.Button(self.panel, id=2, label="Button2") b3 = wx.Button(self.panel, id=3, label="Button3") self.Bind(event=wx.EVT_BUTTON, handler=self.on_click, id=1, id2=3) vbox = wx.BoxSizer(wx.VERTICAL) vbox.Add(b1, proportion=1, flag=wx.EXPAND | wx.ALL, border=10) vbox.Add(b2, proportion=1, flag=wx.EXPAND | wx.ALL, border=10) vbox.Add(b3, proportion=1, flag=wx.EXPAND | wx.ALL, border=10) vbox.Add(self.sb, proportion=3, flag=wx.EXPAND | wx.ALL, border=10) self.panel.SetSizer(vbox) def on_click(self, event): event_id = event.GetId() if event_id == 1: self.sb.SetBitmap(self.bmps[0]) elif event_id == 2: self.sb.SetBitmap(self.bmps[1]) else: self.sb.SetBitmap(self.bmps[2]) self.panel.Layout() # 重新设置panel面板布局 app = wx.App() frm = MyFrame() frm.Show() app.MainLoop()