wxPython
知识内容:
1.wxPython介绍
2.wxPython组件
3.wxPython布局
4.wxPython事件处理
5.wxPython实战
参考:https://www.yiibai.com/wxpython
一、wxPython介绍
1.wxPython是什么
官方解释:wxPython, the cross-platform GUI toolkit for the Python language. With wxPython software developers can create truly native user interfaces for their Python applications, that run with little or no modifications on Windows, Macs and Linux or other unix-like systems
翻译过来就是:wxPython是python中的跨平台的GUI工具,可以使用它给python程序快速搭建用户界面,可以运行到各种操作系统中
2.wxPython安装及基本使用
(1)安装
使用pip安装或在pycharm中的设置中直接安装
(2)基本使用
使用wxPython创建GUI程序的三个主要步骤如下:
- 导入wxPython包
- 建立框架类
- 建立主程序
下面是以上三步骤的实例:
1 # __author__ = "wyb" 2 # date: 2018/4/29 3 4 import wx # 1.导入wxPython 5 6 7 # 2.建立框架类 8 class MyFrame(wx.Frame): 9 def __init__(self, superior): 10 wx.Frame.__init__(self, parent=superior, title=u'first', size=(500, 500)) 11 self.Bind(wx.EVT_SIZE, self.OnSize) 12 self.Bind(wx.EVT_MOVE, self.OnFrameMove) 13 14 panel = wx.Panel(self, -1) 15 label1 = wx.StaticText(panel, -1, "FrameSize:") 16 label2 = wx.StaticText(panel, -1, "FramePos:") 17 label3 = wx.StaticText(parent=panel, label="MouseSize:") 18 self.sizeFrame = wx.TextCtrl(panel, -1, "", style=wx.TE_READONLY) 19 self.posFrame = wx.TextCtrl(panel, -1, "", style=wx.TE_READONLY) 20 self.posMouse = wx.TextCtrl(panel, -1, "", style=wx.TE_READONLY) 21 panel.Bind(wx.EVT_MOTION, self.OnMouseMove) 22 self.panel = panel 23 24 sizer = wx.FlexGridSizer(3, 2, 5, 5) 25 sizer.Add(label1) 26 sizer.Add(self.sizeFrame) 27 sizer.Add(label2) 28 sizer.Add(self.posFrame) 29 sizer.Add(label3) 30 sizer.Add(self.posMouse) 31 32 border = wx.BoxSizer() 33 border.Add(sizer, 0, wx.ALL, 15) 34 panel.SetSizerAndFit(border) 35 self.Fit() 36 37 def OnSize(self, event): 38 size = event.GetSize() 39 self.sizeFrame.SetValue("%s, %s" % (size.width, size.height)) 40 event.Skip() 41 42 def OnFrameMove(self, event): 43 pos = event.GetPosition() 44 self.posFrame.SetValue("%s, %s" % (pos.x, pos.y)) 45 46 def OnMouseMove(self, event): 47 pos = event.GetPosition() 48 self.posMouse.SetValue("%s, %s" % (pos.x, pos.y)) 49 50 51 # 3.建立主程序 52 if __name__ == '__main__': 53 app = wx.App() # 创建应用程序对象 54 frame = MyFrame(None) # 创建框架类对象 55 frame.Show(True) # 展示框架 56 app.MainLoop() # 开始事件循环
注: 上述具体内容看下面的详细介绍
(3)hello world程序
1 import wx 2 3 app = wx.App() 4 window = wx.Frame(None, title = "hello world", size = (400,300)) 5 panel = wx.Panel(window) 6 label = wx.StaticText(panel, label = "Hello World", pos = (100,100)) 7 window.Show(True) 8 app.MainLoop()
二、wxPython组件
1.Frame组件
(1)Frame简介
Frame也称为框架或窗体,是所有框架的父类,也是包含标题栏、菜单、按钮等其他控件的容器,运行之后可移动、缩放
(2)Frame构造函数
创建GUI程序时,需要继承wx.Frame派生出子类,在子类中调用基类构造函数进行必要的初始化工作,Frame的构造函数格式如下:
1 __init__(self, Window parent, int id=-1, String title=EmptyString, Point pos=DefaultPosition, Size size=DefaultSize, long Style=DEFAULT_FRAME_STYLE, String name=FrameStr)
各参数具体含义如下:
- parent:框架的父窗体,为None表示创建顶级窗体
- id:ID值,为-1时将自动生成一个新id,由系统保证其唯一性
- title:窗体的标题
- pos:指定窗体左上角在屏幕中的位置
- size:指定窗体的大小
- style:指定窗体的类型
- name:指定框架的名字,指定后可以使用这个名字来寻找窗体
注:上述参数中只有parent没有默认值,so最简单的调用方式是wx.Frame.__init__(self, parent=None),这将生成一个默认位置、默认大小、默认标题的顶层窗体
(3)关于id
在wxPython的函数中很多时候要设置id,如果无法确定如何设置id,可以使用wx.NewId()函数来生成id号,这样讲就可以避免ID号唯一的麻烦
例如:
1 frame = wx.Frame__init__(None, wx.NewId()) 2 3 # 设置配置菜单 4 configmenu = wx.Menu() 5 configmenu.Append(wx.NewId(), "自动换行", "选择是否自动换行") 6 configmenu.Append(wx.NewId(), "状态栏", "选择是否显示状态栏")
当然也可以使用全局常量wx.ID_ANY(值为-1)来让wxPython自动生成新的唯一ID号,需要时也可以使用GetId()方法得到它
1 frame = wx.Frame.__init__(None, -1) 2 id = frame.GetId()
(4)wx.Frame类成员函数
S.N. | 函数 & 描述 |
---|---|
1 |
CreateStatusBar() 创建窗口底部状态栏
|
2 |
CreateToolBar() 创建工具栏在窗口的顶部或左侧
|
3 |
GetMenuBar() 获取引用菜单栏
|
4 |
GetStatusBar() 获取引用状态栏
|
5 |
SetMenuBar() 在帧(frame)显示菜单栏对象
|
6 |
setStatusBar() 关联状态栏对象到框架(frame)
|
7 |
SetToolBar() 关联工具栏对象到框架(frame) |
8 |
SetStatusText() 在状态栏上显示的文字
|
9 |
Create() 创建有提供参数的框架
|
10 |
Centre() 放置该帧(frame)显示在中心
|
11 |
SetPosition() 放置帧(frame)在给定的屏幕坐标
|
12 |
SetSize() 由给定尺寸调整框架(frame)大小
|
13 |
SetTitle() 插入给定文本到标题栏
|
(5)wx.Frame 事件绑定器
S.N. | 事件 & 描述 |
---|---|
1 |
EVT_CLOSE 当帧被用户关闭/或以编程方式点击关闭按钮
|
2 |
EVT_MENU_OPEN 当一个菜单即将打开
|
3 |
EVT_MENU_CLOSE 当一个菜单刚刚关闭
|
4 |
EVT_MENU_HIGHLIGHT 当指定id菜单项突显
|
2.按钮、静态文本框、文本框
(1)Button按钮
在任何GUI界面按钮组件的应用最为广泛。它捕获用户生成的点击事件。其最明显的用途是触发绑定到一个处理函数
wx.Button类对象带有一些文本作为其标题,是一个简单易用的按钮
构建Button:Wx.Button(parent=None, label=None, pos=None, size=None)
在上述参数中label是按钮上的文本,pos与size分别是设置位置和大小,parent表示父窗体
wx.Button类的常用方法:
- SetLabel() 编程设置按钮的标题
- GetLabel() 返回按钮的标题
- SetDefault() 按钮设置为默认顶层窗口。模拟click事件按下回车键
(2)StaticText静态文本框
wx.StaticText类对象提供了一个控件持有只读文本,被动控制,不产生任何事件,只是单纯的文本
构建StaticText:Wx.StaticText(parent=None, label=None, pos=None, size=None, style=None)
在上述参数中label是文本,pos与size分别是设置位置和大小,parent表示父窗体。style表示文本的样式
(3)TextCtrl文本框
wx.TextCtrl类的一个对象用于显示文一个多行文本框,TextCtrl小部件可以是单行,多行或密码字段
构建TextCtrl:Wx.TextCtrl(parent=None, value=None, pos=None, size=None, style=None)
在上述参数中value是默认文本,pos与size分别是设置位置和大小,parent表示父窗体。style表示文本框的样式
1 tc_stu_id = wx.TextCtrl(panel) # 普通文本框 2 tc_pwd = wx.TextCtrl(panel,style = wx.TE_PASSWORD) # 密码框 3 tc_lines = wx.TextCtrl(panel,size = (200,100),style = wx.TE_MULTILINE) # 多行文本框 4 5 # 不可编辑文本框: 6 wx.TextCtrl ( panel, value = "ReadOnly Text", style = wx.TE_READONLY | wx.TE_CENTER )
TextCtrl类常用方法:
- GetValue()获取值
- SetValue()设置值
- AppendText()添加值
3.菜单系列(MenuItem Menu MenuBar)
(1)Menu
Menu类用来创建菜单,使用如下:
1 # 设置文件菜单: 2 filemenu = wx.Menu() 3 # 向菜单中添加对象 4 menuNew = filemenu.Append(wx.ID_NEW, "新建", "新建文件") 5 menuOpenFile = filemenu.Append(wx.ID_OPEN, "打开", "打开文件") 6 filemenu.AppendSeparator() # 在菜单中的选项之间加分隔符 7 menuSaveFile = filemenu.Append(wx.ID_SAVE, "保存", "保存文件") 8 filemenu.AppendSeparator() 9 menuExit = filemenu.Append(wx.ID_EXIT, "退出", "退出notebook") 10 11 # 设置编辑菜单 12 editmenu = wx.Menu() 13 # 向菜单中添加对象 14 editmenu.Append(wx.ID_CANCEL, "撤销", "撤销操作") 15 editmenu.Append(wx.ID_PASTE, "粘贴", "粘贴信息") 16 17 # 设置配置菜单 18 configmenu = wx.Menu() 19 # 向菜单中添加对象 20 configmenu.Append(wx.NewId(), "自动换行", "选择是否自动换行") 21 configmenu.Append(wx.NewId(), "状态栏", "选择是否显示状态栏") 22 23 # 设置帮助菜单 24 helpmenu = wx.Menu() 25 # 向菜单中添加对象 26 helpmenu.Append(wx.ID_ABOUT, "关于", "关于notebook") 27 helpmenu.Append(wx.ID_HELP, "帮助", "查看帮助信息")
(2)MenuBar
MenuBar用来创建菜单栏,使用如下:
1 # 创建菜单栏 2 menuBar = wx.MenuBar() 3 menuBar.Append(filemenu, "文件(F)") 4 menuBar.Append(editmenu, "编辑(E)") 5 menuBar.Append(configmenu, "配置(C)") 6 menuBar.Append(helpmenu, "帮助(H)") 7 self.SetMenuBar(menuBar)
(3)MenuItem
一个菜单中的对象可以使用Append方法直接添加,也可以先生成一个MenuItem对象再添加这个对象
1 Item = Wx.MenuItem(parentmenu, id, text, kind) 2 3 wx.Menu.Append(Item)
1 item = wx.MenuItem(filemenu, wx.NewId(), "test", "test") 2 filemenu.Append(item)
4.工具栏及状态栏
(1)ToolBar工具栏
工具栏包括文本文字说明或图标按钮的一个或多个水平条,通常被放置在MenuBar顶层帧的正下方
ToolBar类的构造函数不带任何参数则使用工具栏默认参数。附加参数可以传递给wx.ToolBar类构造如下
Wx.ToolBar(parent, id, pos, size, style)
(2)StatusBar状态栏
创建状态栏及设置状态栏:
1 self.StatusBar = self.frame.CreateStatusBar() 2 self.statusBar.SetStatusText('You clicked the Open menu')
5.对话框
对话框有:
- 简单消息框MessageBox
- 接受用户输入的文本GetTextFromUser
- 接受用户输入的密码GetPasswordFromUser
- 接受用户输入的数字GetNumberFromUser
- 文件对话框FileDialog
- 字体对话框FontDialog
- 颜色对话框ColourDialog
(1)MessageBox
1 finalStr = "OK" 2 wx.MessageBox(finalStr)
(2)FileDialog
wx.FileDialog 允许用户从系统的文件中选择一个或者多个文件。支持通配符,可以让用户选择关心的文件。例如:"BMP files (*.bmp)|*.bmp|GIF files (*.gif)|*.gif"只会显示和选择图片后缀类型是bmp 和gif
6.单选框、复选框、组合框、列表框
(1)RadioButton单选框与CheckBox复选框
常用操作:
1 GetValue() 判断单选或复选是否被选中 2 SetValue() 设置单选或复选的选中状态(参数为True表示选中,否则表示未选中)
在某些应用中可能需要响应单选框、复选框的鼠标点击事件,可以使用wx.EVT_RADIOBOX(),wx.CHECKBOX()分别为单选框和复选框来绑定事件处理函数
单选框与复选框应用:
1 # __author__ = "wyb" 2 # date: 2018/5/7 3 import wx 4 5 6 class wxGUI(wx.App): 7 def OnInit(self): 8 self.frame = wx.Frame(parent=None, title='wxGUI', size=(300, 300)) 9 self.panel = wx.Panel(self.frame, -1) 10 11 # 单选框 所有的选项中只能选一种 12 self.radioButtonSexM = wx.RadioButton(self.panel, -1, 'Male', pos=(80, 60)) 13 self.radioButtonSexF = wx.RadioButton(self.panel, -1, 'FeMale', pos=(80, 80)) 14 # 复选框 可以不选或选一种或多选 15 self.checkBoxAdmin = wx.CheckBox(self.panel, -1, 'Administrator', pos=(150, 60)) 16 self.checkBoxRoot = wx.CheckBox(self.panel, -1, 'Root', pos=(150, 80)) 17 18 self.label1 = wx.StaticText(self.panel, -1, 'username: ', pos=(0, 110), style=wx.ALIGN_RIGHT) 19 self.label2 = wx.StaticText(self.panel, -1, 'password: ', pos=(0, 130), style=wx.ALIGN_RIGHT) 20 21 self.textName = wx.TextCtrl(self.panel, -1, pos=(70, 110), size=(160, 20)) 22 self.textPwd = wx.TextCtrl(self.panel, -1, pos=(70, 130), size=(160, 20), style=wx.TE_PASSWORD) 23 24 # 建立OK按钮并绑定事件 25 self.buttonOK = wx.Button(self.panel, -1, 'OK', pos=(30, 160)) 26 self.Bind(wx.EVT_BUTTON, self.OnButtonOK, self.buttonOK) 27 # 建立Cancel按钮并绑定事件 28 self.buttonCancel = wx.Button(self.panel, -1, 'Cancel', pos=(120, 160)) 29 self.Bind(wx.EVT_BUTTON, self.OnButtonCancel, self.buttonCancel) 30 self.buttonOK.SetDefault() # 设置默认选择OK按钮 31 32 self.frame.Show() 33 return True 34 35 # OK按钮的响应事件 36 def OnButtonOK(self, event): 37 finalStr = '' 38 if self.radioButtonSexM.GetValue() == True: 39 finalStr += 'Sex: Male\n' 40 elif self.radioButtonSexF.GetValue() == True: 41 finalStr += 'Sex: FeMale\n' 42 if self.checkBoxAdmin.GetValue() == True: 43 finalStr += 'Administrator\n' 44 if self.textName.GetValue() == 'wyb' and self.textPwd.GetValue() == 'wyb': 45 finalStr += 'login' 46 else: 47 finalStr += 'wrong username or wrong password!' 48 wx.MessageBox(finalStr) 49 50 # Cancel按钮的响应事件 51 def OnButtonCancel(self, event): 52 self.radioButtonSexM.SetValue(True) 53 self.radioButtonSexF.SetValue(False) 54 self.checkBoxAdmin.SetValue(True) 55 self.textName.SetValue('') 56 self.textPwd.SetValue('') 57 58 59 if __name__ == '__main__': 60 app = wxGUI() 61 app.MainLoop()
(2)ComboBox组合框
组合框用来实现从固定的多个选项中选择其中一个的操作,外观与文本框类似,但是单击下拉箭头时弹出所有可选项,极大地方便了用户的操作,并且在窗体上不占用太多空间
如果需要响应和处理组合框的鼠标单击事件,可以使用wx.EVT_COMBOBOX()为组合框绑定事件处理函数,组合框实例如下:
1 # __author__ = "wyb" 2 # date: 2018/5/8 3 import wx 4 5 class wxGUI(wx.App): 6 def OnInit(self): 7 self.frame = wx.Frame(parent=None, title='wxGUI', size=(300, 200)) 8 self.panel = wx.Panel(self.frame, -1) 9 self.names = {'北京': ['东城', '海淀', '朝阳'], '武汉': ['武昌', '汉口', '汉阳']} 10 11 # ComBox1 12 # print(self.names.keys()) 13 print(list(self.names.keys())) 14 self.comboBox1 = wx.ComboBox(self.panel, value='请选择', choices=list(self.names.keys()), pos=(0, 50), size=(100, 30)) 15 self.Bind(wx.EVT_COMBOBOX, self.OnCombo1, self.comboBox1) 16 17 # ComBox2 18 self.comboBox2 = wx.ComboBox(self.panel, value='请选择', choices=[], pos=(0, 100), size=(100, 30)) 19 self.Bind(wx.EVT_COMBOBOX, self.OnCombo2, self.comboBox2) 20 21 self.frame.Show() 22 return True 23 24 def OnCombo1(self, event): 25 k = self.comboBox1.GetValue() 26 self.comboBox2.Set(self.names[k]) # 动态修改第二个组合框中的值 27 28 def OnCombo2(self, event): 29 wx.MessageBox(self.comboBox2.GetValue()) # 弹出选择的第二个组合框中的值 30 31 app = wxGUI() 32 app.MainLoop()
(3)ListBox列表框
列表框用来放置多个元素提供给用户进行选择,其中每个元素都是字符串,支持用户单选和多选,组合框实例如下:
1 # __author__ = "wyb" 2 # date: 2018/5/10 3 import wx 4 5 6 class ListBoxDemo(wx.Frame): 7 def __init__(self, superion): 8 wx.Frame.__init__(self, parent=superion, title='ListBox demo', size=(200, 200)) 9 panel = wx.Panel(self) 10 self.buttonQuit = wx.Button(parent=panel, label='Quit', pos=(60, 120)) 11 self.Bind(wx.EVT_BUTTON, self.OnButtonQuit, self.buttonQuit) 12 li = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'] 13 self.listBox = wx.ListBox(panel, choices=li) # 创建列表框 14 self.Bind(wx.EVT_BUTTON, self.OnClick, self.listBox) # 绑定事件处理器 15 16 def OnClick(self, event): 17 t = self.listBox.GetSelection() 18 s = self.listBox.GetString(t) 19 print(s) 20 s = self.listBox.GetStringSelection() 21 wx.MessageBox(s) 22 23 def OnButtonQuit(self, event): 24 dlg = wx.MessageDialog(self, 'Really Quit?', 'Caution', wx.CANCEL|wx.OK|wx.ICON_QUESTION) 25 if dlg.ShowModal() == wx.ID_OK: 26 self.Destroy() 27 28 29 if __name__ == '__main__': 30 app = wx.App() 31 frame = ListBoxDemo(None) 32 frame.Show() 33 app.MainLoop()
三、wxPython布局
1.wxPython布局简介
布局方法:绝对定位和相对定位,绝对定位是指一个GUI部件可通过指定以像素为单位的绝对坐标放置在容器窗口中。 坐标是相对于它的构造尺寸参数定义的窗口的尺寸大小。窗口中的窗口小部件的位置由它的构造函数的pos参数定义的
绝对定位实例:
1 import wx 2 3 app = wx.App() 4 window = wx.Frame(None, title = "wxPython Frame", size = (300,200)) 5 panel = wx.Panel(window) 6 label = wx.StaticText(panel, label = "Hello World", pos = (100,50)) 7 window.Show(True) 8 app.MainLoop()
而在wxPython中的相对定位是指使用布局类容器来定位,wxPython的API提供了布局类的容器内的小部件的定位更优雅的管理:
-
在窗口中的窗口小部件会自动调整大小
-
确保均匀的外观上不同分辨率的显示设备
-
添加或去除部件动态地是可能的,而不需要重新设计
布局管理器在wxPython中被称为Sizer。Wx.Sizer是所有sizer 的基类。一些重要的sizer有wx.BoxSizer,wx.StaticBoxSizer,wx.GridSizer,wx.FlexGridSizer
我的博客中主要介绍BoxSizer布局和GridSizer布局这两种方法
2.BoxSizer布局
BoxSizer布局是由它的定位参数(wxVERTICAL或wxHORIZONTAL)确定
- Box = wx.BoxSizer(wxHORIZONTAL) -> 水平布局(从左到右添加组件)
- Box = wx.BoxSizer(wxVERTICAL) -> 垂直布局(从上到下添加组件)
3.GridSizer布局
一个GridSizer对象展示二维网格。控件被添加在网格插槽从左到右和由上到下方顺序。GridSizer对象有四个参数
Box = wx.GridSizer(rows, columns, vgap, hgap) -> vgap和hgap指定参数控制相邻控件之间的纵向和横向间距,rows和columns分别指定行数和列数
GridSizer布局实例:
1 import wx 2 class Example(wx.Frame): 3 def __init__(self, parent, title): 4 super(Example, self).__init__(parent, title = title,size = (300,200)) 5 self.InitUI() 6 self.Centre() 7 self.Show() 8 9 def InitUI(self): 10 p = wx.Panel(self) 11 r = wx.GridSizer(4, 4, 5, 5) 12 13 for i in range(1,17): 14 btn = "Btn"+str(i) 15 r.Add(wx.Button(p,label = btn),0,wx.EXPAND) 16 17 p.SetSizer(r) 18 19 app = wx.App() 20 Example(None, title = 'Grid Demo’) 21 app.MainLoop()
四、wxPython事件处理
点击一个按钮发出 wx.CommandEvent 事件。该事件数据被分派到程序事件处理的方法。wxPython中有许多预定义的事件绑定器。一个事件绑定封装了具体的小部件(控件),其关联的事件类型和事件处理方法之间的关系
五、wxPython实战
1.判断素数
1 # __author__ = "wyb" 2 # date: 2018/5/7 3 4 import wx 5 from math import sqrt 6 7 8 class IsPrimeFrame(wx.Frame): 9 def __init__(self, superion): 10 wx.Frame.__init__(self, parent=superion, title="Check Prime", size=(400, 200)) 11 panel = wx.Panel(self) 12 panel.SetBackgroundColour('White') 13 wx.StaticText(parent=panel, label='Input a integer:', pos=(10, 10)) 14 self.inputN = wx.TextCtrl(parent=panel, pos=(120, 10)) 15 self.result = wx.StaticText(parent=panel, label='', pos=(10, 50)) 16 self.buttonCheck = wx.Button(parent=panel, label='Check', pos=(70, 90)) 17 18 self.Bind(wx.EVT_BUTTON, self.OnButtonCheck, self.buttonCheck) 19 self.buttonQuit = wx.Button(parent=panel, label='Quit', pos=(150, 90)) 20 self.Bind(wx.EVT_BUTTON, self.OnButtonQuit, self.buttonQuit) 21 22 def OnButtonCheck(self, event): 23 self.result.SetLabel('') 24 try: 25 num = int(self.inputN.GetValue()) # 获取用户输入的数字 26 except BaseException as e: 27 self.result.SetLabel('not a integer!') 28 return 29 n = int(sqrt(num)) 30 for i in range(2, n + 1): 31 if num % i == 0: 32 self.result.SetLabel("No") 33 else: 34 self.result.SetLabel("Yes") 35 36 def OnButtonQuit(self, event): 37 dlg = wx.MessageDialog(self, 'Really Quit?', 'Caution', wx.CANCEL | wx.OK | wx.ICON_QUESTION) 38 if dlg.ShowModal() == wx.ID_OK: 39 self.Destory() 40 41 42 if __name__ == '__main__': 43 app = wx.App() 44 frame = IsPrimeFrame(None) 45 frame.Show() 46 app.MainLoop()
2.学生信息
1 import wx 2 3 4 class StudentGUI(wx.Frame): 5 def __init__(self): 6 wx.Frame.__init__(self, parent=None, title="studentGUI", size=(600, 450)) 7 self.infos = [] # 存储所有的学生信息 8 self.InitUI() 9 self.Centre() 10 self.Show() 11 12 def InitUI(self): 13 panel = wx.Panel(self) 14 # 整体: 15 hbox = wx.BoxSizer(wx.HORIZONTAL) 16 # 第一列和第二列 17 vbox1 = wx.BoxSizer(wx.VERTICAL) 18 vbox2 = wx.BoxSizer(wx.VERTICAL) 19 20 # 第一列分为上下两部分 21 hbox1 = wx.BoxSizer(wx.HORIZONTAL) 22 hbox2 = wx.BoxSizer(wx.HORIZONTAL) 23 24 # 第一列的上部分又分为左右两部分 25 hbox1_v1 = wx.BoxSizer(wx.VERTICAL) 26 hbox1_v2 = wx.BoxSizer(wx.VERTICAL) 27 28 # 第一列的上部分的左边 29 hbox1_v1.AddSpacer(10) 30 stu_id = wx.StaticText(panel, label='学号:') 31 hbox1_v1.Add(stu_id, flag=wx.RIGHT, border=8) 32 hbox1_v1.AddSpacer(10) 33 stu_name = wx.StaticText(panel, label='姓名:') 34 hbox1_v1.Add(stu_name, flag=wx.RIGHT, border=8) 35 hbox1_v1.AddSpacer(10) 36 stu_cj = wx.StaticText(panel, label='成绩:') 37 hbox1_v1.Add(stu_cj, flag=wx.RIGHT, border=8) 38 hbox1_v1.AddSpacer(10) 39 stu_c = wx.StaticText(panel, label='C:') 40 hbox1_v1.Add(stu_c, flag=wx.RIGHT, border=8) 41 hbox1_v1.AddSpacer(10) 42 stu_cpp = wx.StaticText(panel, label='C++:') 43 hbox1_v1.Add(stu_cpp, flag=wx.RIGHT, border=8) 44 hbox1_v1.AddSpacer(10) 45 stu_math = wx.StaticText(panel, label='高数:') 46 hbox1_v1.Add(stu_math, flag=wx.RIGHT, border=8) 47 48 # 第一列的上部分的右边 49 hbox1_v2.AddSpacer(8) 50 self.tc_stu_id = wx.TextCtrl(panel) 51 hbox1_v2.Add(self.tc_stu_id, proportion=1) 52 hbox1_v2.AddSpacer(5) 53 self.tc_stu_name = wx.TextCtrl(panel) 54 hbox1_v2.Add(self.tc_stu_name, proportion=1) 55 hbox1_v2.AddSpacer(30) 56 self.tc_score_c = wx.TextCtrl(panel) 57 hbox1_v2.Add(self.tc_score_c, proportion=1) 58 hbox1_v2.AddSpacer(5) 59 self.tc_score_cpp = wx.TextCtrl(panel) 60 hbox1_v2.Add(self.tc_score_cpp, proportion=1) 61 hbox1_v2.AddSpacer(5) 62 self.tc_score_math = wx.TextCtrl(panel) 63 hbox1_v2.Add(self.tc_score_math, proportion=1) 64 # 把第一列上部分的左右加到第一列上部分 65 hbox1.Add(hbox1_v1) 66 hbox1.AddSpacer(25) 67 hbox1.Add(hbox1_v2) 68 69 # 第一列的下部分 70 button_sum = wx.Button(panel, -1, "总成绩") 71 button_continue = wx.Button(panel, -1, "继续输入") 72 hbox2.Add(button_sum) 73 hbox2.Add(button_continue) 74 75 # 把第一列的上部分和下部分加到第一列中 76 vbox1.Add(hbox1, 1, wx.ALL | wx.EXPAND) 77 vbox1.AddSpacer(10) 78 vbox1.Add(hbox2, 1, wx.ALL | wx.EXPAND) 79 80 # 第二列 81 vbox2.AddSpacer(8) 82 stu_infos = wx.StaticText(panel, label='学生考试信息:') 83 vbox2.Add(stu_infos, flag=wx.RIGHT, border=8) 84 stu_details = wx.StaticText(panel, label=' 学号 姓名 C C++ 高数 总成绩:') 85 vbox2.Add(stu_details, flag=wx.RIGHT, border=8) 86 self.info_list = wx.TextCtrl(panel, style=wx.TE_MULTILINE, size=(350, 350)) 87 vbox2.Add(self.info_list, 1, wx.EXPAND, 10) 88 vbox2.AddSpacer(5) 89 button_sort = wx.Button(panel, -1, "按总分降序排序") 90 vbox2.Add(button_sort, 0, wx.ALIGN_CENTER_HORIZONTAL) 91 vbox2.AddSpacer(15) 92 93 # 把第一列和第二列加到整个整体中 94 hbox.Add(vbox1, 1, wx.ALL | wx.EXPAND) 95 hbox.AddSpacer(10) 96 hbox.Add(vbox2, 1, wx.ALL | wx.EXPAND) 97 hbox.AddSpacer(10) 98 99 # 绑定事件: 100 self.Bind(wx.EVT_BUTTON, self.cal_sum, button_sum) 101 self.Bind(wx.EVT_BUTTON, self.continue_input, button_continue) 102 self.Bind(wx.EVT_BUTTON, self.sort, button_sort) 103 104 panel.SetSizer(hbox) 105 106 def cal_sum(self, event): 107 info = dict() # 存储学校信息的字典 108 info["id"] = self.tc_stu_id.GetValue() 109 info["name"] = self.tc_stu_name.GetValue() 110 info["c"] = int(self.tc_score_c.GetValue()) 111 info["cpp"] = int(self.tc_score_cpp.GetValue()) 112 info["math"] = int(self.tc_score_math.GetValue()) 113 info["sum"] = info["c"] + info["cpp"] + info["math"] 114 self.infos.append(info) 115 self.info_list.AppendText("%s\t%s\t%d\t%d\t%d\t%d\n" % (info["id"], info["name"], info["c"], info["cpp"], info["math"], info["sum"])) 116 117 def continue_input(self, event): 118 self.tc_stu_id.SetValue("") 119 self.tc_stu_name.SetValue("") 120 self.tc_score_c.SetValue("") 121 self.tc_score_cpp.SetValue("") 122 self.tc_score_math.SetValue("") 123 124 def sort(self, event): 125 self.info_list.Clear() # 清空之前的文本框 126 details = self.infos 127 sums, sort_info = [], [] 128 for detail in details: 129 sums.append(detail["sum"]) 130 for i in range(len(sums)): 131 max_sum = max(sums) 132 index = sums.index(max_sum) 133 sums[index] = 0 134 sort_info.append(details[index]) 135 for info in sort_info: 136 self.info_list.AppendText("%s\t%s\t%d\t%d\t%d\t%d\n" % (info["id"], info["name"], info["c"], info["cpp"], info["math"], info["sum"])) 137 138 139 if __name__ == '__main__': 140 app = wx.App() 141 frame = StudentGUI() 142 # frame.Show() 143 app.MainLoop()