目录 主要使用wxPython(最成熟的跨平台python GUI工具包) 前戏:基础了解 WxPython的程序结构 窗口组成: 事件驱动: 常用组件(简单了解,后面还有): 基本组件 1.静态文本框 2.文本输入框 3.按钮控件 4.单选框 5.多选框 6.列表控件 7.使用sizer布局组件 菜单,窗口,对话框组件 菜单 窗口 对话框 窗口和对话框的交互 高级控件 表格控件 高级列表控件 树形控件 树表控件 定时器控件 WxPython库中的高级功能
主要使用wxPython(最成熟的跨平台python GUI工具包)
前戏:基础了解

View Code
补充:id是什么:wxpython对每个控件都会分配一个唯一的整数型ID,方便调用,类十余c中的Handle。ID在时间响应中必不可少。
创建控件时如果ID为-1时,会自动分配一个ID。这样就不能对ID进行引用。其实可以使用控件对象的GetId方法进行获取
前提: 唯一ID的生成:wx提供了NewId(),可以生成唯一的id。(若担心重复,可以使用RegisterID检测)
我们想要使用ID,但是程序中控件太多,如何处理
方法一:前置每个控件的ID(自己设置的名称),使用列表生成器生成
[Btn_1_ID,Btn_2_ID,Btn_3_ID] = [wx.NewId() for _init_cj in range(3)]有几个控件就设置循环几次
然后在生成控件时进行调用
方法二:使用类的属性来预先分配,然后控件类对他进行继承,每个控件类句读一个属于他的id属性
一个WxPython程序一般包含两个对象:应用程序对象和根窗口(可多个)。其中,应用程序对象可以使用wx.App(或子类)实现(用于处理窗口中的事件响应),根窗口可以使用wx.Frame实现。

App子类的使用
其中OnInit方法中是必须的,其将会在事件循环处理之前被系统调用。同样的在事件结束之后调用的方法也存在(OnExit)
两个方法是相对的。例如:开启数据库和断开数据库
前面的代码中窗口和应用程序似乎没有关联,为什么?
在应用程序对象中,可以通过SetTopWindow方法来设置根窗口。若是没有设置,是因为应用程序会选择窗口列表中的第一个作为根窗口。上面的程序也只有一个窗口,所以没有必要去显示设置。同样使用SetTopWindow也可以改变根窗口
控件的部分构造参数:
<col>
参数
说明
parent
父窗口(为None代表为顶级窗口),注意设置父窗口后,在父窗口关闭时,子窗口也会消失
id
上面说过了
title
标题
pos
相对于屏幕的位置默认(-1,-1),自行选择。我们在上面使用center也可以改变窗口在屏幕中的位置
size
大小默认(-1,-1)窗口系统自行选择
style
窗口类型...
name
窗口的内在名字
style风格:

所有支持的事件类型(上百个)
一个事件是wx.Event类或其子类的一个实例。
事件的绑定和处理:通过使用wx.EvtHandler类中的Bind方法可以将绑定事件的类型,事件对象和事件处理函数关联起来

def Bind(self, event<事件类型>, handler<处理函数>, source=None<事件的发生者:不写默认当前控件>, id=-1, id2=-1)

事件绑定和处理的演示

为一个控件绑定多个事件
补充:
方式一:是是由父控件为子控件绑定的事件
方式二:是使用控件自己绑定事件
那么两者有何不同,可以混用吗
答案是:父类去绑定其他事件是不允许的,错误的,会导致父控件为其绑定的所有事件失效。而子类是可以绑定所有的相关事件的。
查看事件对象:
这一类事件都是对应控件去响应的,也就是说父类中包含这些控件的话,可以对其直接绑定这些基础事件响应。
所以说:要想使用父控件对子控件绑定事件:事件必须满足 EVT_控件名 相对应
为同一个控件的同一个事件,绑定两个(多个)处理函数。
其执行结果是只执行了事件处理函数2:原因是因为:一般情况下,窗口部件对象在执行完该事件的一个处理函数,就默认完结了。不会再去处理其他相关的函数。而,事件绑定是从上到下,下面的会覆盖上面的,所以,值执行了处理函数了。
我们要想去执行其他函数,那么就要在正在执行的处理函数后面加上event.Skip(),他会在当前函数返回一个值后去调用下一个处理函数,改变原来的默认行为。

工具栏
Realize() 方法需要被调用,以最终确定工具栏创建

StaticText和字体的设置Font

文本输入框TextCtrl的设置size()设置-1代表默认
相关参数:
常用方法:

TextCtrl根据参数设置多行文本框,使用方法设置背景色

普通按钮Button

位图按钮,以及图片的转换
补充:图片转换

RadioButton的使用,以及事件对象获取GetEventObject,获取对象标签GetLabel

RadioBox单选框组的使用,可以为框组设置事件处理,使用self.框组.GetStringSelection获取label值

CheckBox的使用(全选和反选数据处理)

同样也有多选列表框CheckListBox

ListBox和CheckListBox控件的使用和事件处理
listbox样式:

Choice下拉框

可编辑下拉框ComboBox(是Choice的子类,可以使用它的方法)
combobox的样式:
前面的程序都是通过设置构造函数的pos,size属性调整控件之间的位置。不太容易掌控位置。wxpython提供了Sizer布局管理器自动设置控件之间的位置。
使用步骤:
创建Sizers布局管理器。布局管理器分为grid sizer, flex grid sizer, grid bag sizer, box sizer,(都是继承父类Sizer)
调整SetSizer()将布局管理器添加到容器中,这里的容器一般指窗口,panel面板等组件。这样就建立了布局管理器和窗口之间的联系。
def SetSizer(self, sizer, deleteOld=True)
调用容器的Add()方法将各个组件添加到布局管理器中.
Add(self,item, proportion=0, flag=0, border=0, userData=None)
其中item是添加到布局管理器中的组件,
proportion是表示当前窗口大小发生改变时,控件之间的比例
flag表示窗口风格,对齐方式,边框等信息
border边框大小(前提是flag设置了边框)
userdata用于传递额外的数据
调用容器的Fit()方法计算布局管理器和容器窗口的大小,来自动调整窗口大小,使其适合当前窗口。
Fit(self)
grid sizer布局是采用表格的形式分配各种控件,不需要设置控件在容器中的位置,直接添加到grid sizer布局管理器中即可

GridSizer简单使用
是对grid sizer的改进。可以用于存放大小可以改变的组件。
相对于Grid Sizer而言,他们的区别主要在于:
FlexGridSizer可以设置某一列或行的可变大小。主要在于下面的几个方法:
其中FlexGridSizer的本身是固定不变的而Grid Sizer是随着窗口的变化,也会改变

FlexGridSizer的使用(不使用专有方法:是不可变的)

GridSizer和上面比较
使用特殊方法,来实现FlexGridSizer的专有属性

FlexGridSizer中的AddGrowableRow和AddGrowableCol
最后:符合我们所希望的:
这就是FlexGridSizer的特征

全部代码
比FlexGridSize更加强大,可以是某个空间添加到特定的单元格,可以实现跨行,跨列显示

GridBagSizer的使用
box sizer是布局管理器中最简单,最灵活的一种布局,可以水平或垂直排列,是各个组件从左到右或从上到下排列在同一条线上。也可以嵌套使用。水平排列的布局可以嵌套水平或垂直排列的布局。这样是应用程序的布局更加灵活
补充:对于上面的布局也可以使用
对齐标志
边界标志:
行为标志:

BoxSizer布局的使用
补充:上面说的proportion比例问题

BoxSizer中;了解proportion
比例只在box中有效,在其他布局中无效(有表格进行约束,不需要控件比例,但是可以用设置最小大小SetMinSize()来设置大小)
(1)创建菜单栏:调用wx.MenuBar创建菜单栏。
(2)创建父菜单。调用wx.Menu类创建父菜单。
(3)将父菜单添加到菜单栏中。调用菜单栏MenuBar类中的Append方法。
(4)添加子菜单,调用Menu类的Append方法直接添加子菜单
(5)添加菜单事件:wx,EVT_MENU
(6)在窗口中添加上菜单栏:

菜单创建代码
MenuBar常用方法:
菜单的响应事件(除了上面的wx.EVT_MENU外):

菜单事件响应以及self.GetMenuBar()获取菜单栏等相关操作

多级菜单设置(一级一级向上添加)
Menu类的常用方法:
使用&来形成快捷键
对于父类菜单,一般快捷键是展开子菜单,Alt + m展开子菜单,再按下q快捷键退出

快捷键的定义
助记符在同一个菜单中是唯一的,在整个菜单栏中可以重复

MenuItem创建子菜单,再使用SetBitmap设置图片,追加到菜单中即可
也是由Menu类创建的,只需要在上下文显示的容器中绑定wx.EVT_CONTEXT_MENU事件,然后又容器组件(如Panel)调用PopupMenu()方法弹出上下文菜单即可

PopupMenu弹出菜单和EVT_CONTEXT_MENU事件
用户的所有操作都是在窗口中完成的,wxPython使用wx.Frame类创建窗口。Frame类的构造函数:

简单的Frame窗口

含有工具栏的菜单栏的Frame窗口:CreateToolBar创建工具栏,Realize来显示。CreateStatusBar创建状态栏
多文档程序窗口可以创建子窗口,子窗口有MDI多文档窗口管理和控制。使用MDIParentFrame创建

MDIParentFrame的使用

多文档界面创建子窗口MDIChildFrame

MiniFrame默认不带窗口操作按钮关闭等)可以设置,而且不会显示在任务栏

Dialog的使用(控件类之间的调用)

MessageDialog提示对话框,注意记得对生成的其他对话框或窗口进行释放,使用Destroy

TextEntryDialog文本输入对话框

FileDialog文件对话框的使用

FontDialog的使用(注意获取字体时需要先获取所有字体的数据,再从中获取选中的字体对象,在进行设置)

窗口交互(Validator数据验证的使用)
注意:
对话框的组件支持验证能力,而窗口不支持组件的验证(不会去自动调用,我们可以自己去调用,但是何必呢)
其中似乎都没有用到验证类中的Validate方法(这个才是我们的验证函数吧),也没有去自动调用TraFromWindow(不是说在对话框关闭时调用吗)。都没有为我们进行调用。那我们是不是可以自己来调用。
在对话框关闭前我们自行调用TraFromWindow方法....(太扯了点....应该如何去正确的使用??)
上面的方法纯属参考。毕竟文档中说了这些预留方法会自动调用,而我们对validate和transferfromwindow都是自行调用的,不太妥当...
表格控件Grid是wxPython中最复杂的控件之一,表格控件通常用于浏览数据。这里介绍表格控件的创建,单元格的设置,表格对象的使用

grid.Grid表格控件的使用
创建步骤:
(1)需要先导入wx.grid包,其中wx.grid包中提供了创建和控制表格的类和方法。
(2)实例化表格类
(3)创建表格控件,numRows是行数,numCols是列数
(4)设置行标题和列标题
(5)设置单元格的值
可以定制更加复杂的表格。通过继承PyGridTableBase类可以实现对表格控件更加复杂的设置。其中继承PyGridTableBase类必须实现GetNumberRows(),GetNumberCols(),GetValue()和SetValue()这些方法。表格会根据这些方法中(Get开头的方法中设置的返回值)的返回值来默认设置值

GetNumberCols

GetNumberRows

GetValue

SetValue(是用来当用户设置值时会调用)
都有说:Must be overridden
注意要想设置属性,先要加上GetAttr()

GridTableBase的使用(设置奇数行颜色为黄色)
注意:table表格是基于表格控件的
注意:设置属性的时候需要对属性加一个引用计数
在我们加上引用计数时,每一次获取都是4(self.evenAttr或self.oddAttr是一次,attr是一个,IncRef增加一次,作为参数传入sys.getrefcount中产生一次,一个四次)
但是我们每次产生一个表格都会对self.evenAttr或者self.oddAttr进行一次计数增加,那么为何依旧是4。
因为在对一个单元格设置属性后,会认为这个值不会再拿去给其他表格使用。所以会在设置属性后减少一个引用计数,而且GetAttr执行完后attr销毁,sys,getrefcount结束都会减少一个计数,所以若是我们不进行引用计数增加的话,会在执行一个GetAtrr(){注:这里有两个属性,会执行两次},该调用的属性会由于引用计数为0,被销毁。导致表格无法生成。
表格控件的单元格可以根据不同的数据需求进行设置。例如:可以把 某个单元格设置为下拉框,复选框,数字选择等控件。wx.grid包提供了一系列的Editor编辑器,这些编辑器都可以在单元格中实现上面需要的控件。除外单元格还可以对数据的字体,颜色,格式进行设置。

单元格的属性设置以及插入控件

事件处理
注意事件是绑定在整个表格,而不是某个单元格
ListCtrl是出具显示的另一种方式。可以提供详细列表,图标列表等显示方式。ListCtrl控件的列对齐,排序等富足功能可以通过继承wx.lib.mixins.listctrl包的mixin类实现
ListCtrl控件常用列表方式显示信息,可以进行排序,地址列表的显示样式。创建方式
1直接实例化wx.ListCtrl类,然后关联列表数据。
2自定义列表控件类,继承wx.ListCtrl或wx.lib.mixins.listctrl包中的mixin类。这些mixin类实现了一些辅助性的功能。例如对齐,排序

列表控件的创建
InseItem是插入一行,默认自己包含一列
参数1:是插入的行的索引,这里我们设置了为0,那么意味着每次插入一条数据,都会插入在第一条,形成了倒序排列(一般我们会将这个参数设置为一个大数,因为显示的时候会去找到第一条数据然后向下显示《会将空白行跳过》)
参数2:就是我们的为默认的那一列设置的默认值(可以不用设置,因为在后面,我们进行了替换)
列表控件的排序
其中对ListCtrl列表排序的总结不错。但是使用的是python2版本。我这里使用python3

列表排序全部代码
注意点:
1.数据的索引必须以0开始:
因为他会调用函数去操作数据。且从0开始去索引,你的数据中没有索引0,那么会报错
2.需要实现几个特定方法,当我们使用ColumnSorterMixin时,必须去实现
(1)必须实现GetListCtrl用于返回创建的列表,因为在进行排序的时候没需要用到列表,而列表的获取是调用GetListCtrl获取
因为MyFrame类继承了ColumnSorterMixin类,所以必须由他来实现这个方法。此外也是需要他去实现(3)
(2)这个让我找了半天...先说3
(3)itemDataMap,对其赋值(赋予我们添加在列表中的值,带上所以,方便映射).注意itemDataMap和ListCtrl控件的创建都要在ColunSorterMixin构造函数执行之前完成,不然会报错
补充(2):他说我们需要去在列表控件类中使用SetItemData去设置一个唯一的值为每一行
那么查看定义:
代码:
SetItemData中的第二个参数data不是我们所定义的数据,而是与数据(itemDataMap)之间的映射。
而这里itemDataMap我们设置的是data全局变量。他和我们这里设置给每行的数据是对应的。而我们这里的index也是从0开始递增的(默认跳过空行,虽然我们在插入的时候随便设置了一个大数,但是由于前面为空,所以还是从0开始)。所以和数据的索引对上号了。我们就可以将两个映射都写为index即可。
注意一点:我们设置的初始排序方法,不能为倒序。若是我们设置的初始排序方式为倒序,那么在插入每一行时。都会出现:插入的数据返回的索引都是0(因为插入数据行都会向前出入,我们无法获取真正的索引,无法与数据建立映射)

AssignImageList和InsertImageStringItem去创建位图列表
1.使用ImageList对象存储图标资源wx.Bitmap对象
2.创建ListCtrl控件,并始终style为wx.LC_ICON
3.调用AssignImageList()方法关联ImageList对象
4.调用InsertImageStringItem()方法出入列表项,并未图标设置说明字符串
树形控件采用分层的方式显示复杂数据,数据呈现父子结构的关系。(分级)

简单创建树形控件
(1)创建TreeCtrl类的实例。下面创建了树形对象tree
(2)调用TreeCtrl类的AddRoot方法添加根节点。并获取该节点
(3)调用自定义函数去递归添加子节点,调用AppendItem(parent,node)为父节点,添加上子节点。
树形控件的事件主要有节点的选择时间,展开时间,合并时间等。当树形控件创建完成后,直接为他绑定相关的事件类型,然后实现相应的处理函数即可。

主要的三个事件触发
树表控件:结合了上面的树形控件和列表控件的风格。既存在父子关系,有可以按照列来显示数据。具备两者的属性和方法。
步骤:
(1)wx.gizmos包中的TreeListCtrl类可以创建树表控件,所以需要先进行导入
(2)创建TreeListCtrl类的实例
(3)可以调用SetImageList()方法设置树表控件中节点所会需要用到的图标。
(4)调用AddColumn()方法可以添加列,并设置列名
(5)调用AddRoot()方法添加树表的根节点。即在第一行第一列中添加根节点
(6)同样可以为这第一行的其他列设置值(SetItemText中的第一个参数是该行标志)
(7)调用AppendItem()方法在父节点下面在添加子节点。下面在root根节点下面添加子节点
(8)调用SetItemText()方法可以对该子节点的列的内容进行设置
(9)可以调用SetItemImage()方法设置树节点的展开,合并图标
实例代码:

树表控件的简单实现
定时器控件时非可视化的控件,用于定时器查询的运行。使用wx.PyTimer,wx.Timer和wx.CallLater类创建定时器控件。定时器类提供了3个主要的方法。Start(mil)方法用于启动定时器,参数mil表示毫秒。Stop()方法用于通知定时器。Restart()方法用于重启定时器,进行新一轮的处理。wx.CallLater类可以向处理程序传递参数,并返回处理程序的计算结果。

定时器实现
1.使用wx.PyTimer定时器会一直进行循环使用start,当然也有其他方法StartOnce只执行一次。Stop去停止定时器。
2.但是我们使用带有参数的定时器时:
默认只会执行一次该定时器,要想继续执行,我们需要在设置的回调函数中在进行重启定时器
执行一次的原因(看源码):
查看执行函数:
这是就想到:在构造函数中就停止了定时器,那么还执不执行定时器了呀?这不是扯淡吗?
接着向下看:
再停止了自己后,就去调用PyTimer定时器了,我去:原来这个类的作用只是对PyTimer的扩充,使得函数可以带上参数了。那么继续向下看如何去执行这个带参数的函数:
大致思路是使用中间类CallLater去获取我们的回调函数名和参数。将函数名和参数存放在自己的成员属性中,然后调用PyTimer类去执行定时器,传入的执行函数名是中间类CallLater定义的一个无参函数,但是在这个方法中执行了成员属性中的回调函数,并向其中传入了参数。
对于一些复杂多样的格式,我们前面使用的样式,有点.....。现在我们可以使用wx.html模块来处理HTML格式的文档。更加方便

HtmlWindow的简单使用
需要引入wx.html模块。使用HtmlWindow类生成一个HTML窗口。可以设置次窗口的内容。但是至少简单内容。style等样式css样式无法使用。

HTML窗口和控件布局结合

LoadPage加载页面
剪切板是在各个应用程序中交换数据的一种方式。一个应用程序可以将数据保存在剪切板中,另一个应用程序可以从剪切板中获取数据、保存的数据可以是文本,图像,或者是其他文件对象。
由于操作系统中的剪切板是全局性的,即对不同的应用程序都是相同的,所以在wxpython程序中剪切板对象是一个全局对象。在操作剪切板之前,需要通过调用Open方法打开次对象,只有此方法返回了True之后,才能够继续使用剪切板。这是因为剪切板是一个全局对象。当其正在被另一个应用程序操作时,我们对剪切板的使用可能会失效。返回false。所以需要对返回值进行检测。也可以使用IsOpened方法来判断。记得在操作结束后调用Close方法将其关闭。阻止占用

TheClipboard剪切板的使用
全部到此结束,若有再会补充,如果想了解进程,线程以及网络等编程在图形界面的编程,可以去试试Qt