GUI是Graphical User Interface(图形用户界面)的缩写,在Gui中,并不是只有键入文本和返回文本,用户可以看到窗口,按钮、文本框等图形,并且可以用鼠标单机,也可以用键盘输入。GUI是与程序交换的种不同方式.GUI的程序有3个基本要素:输入,处理和输出。
一、常用的GUI框架
对于python的GUI开发,有很多工具包供我们选择。以下是一些留下的工具包。
二、安装wxPython
wxPython是一个成熟而且特性丰富的跨平台GUI工具包,使用pip 工具安装wxPython
pip install -U wxPython
使用wxPython之前,先来了解2个基础对象:应用程序对象和顶级窗口
A应用程序对象管理主事件循环,主时间循环是wxPython程序的动力,如果没有应用程序对象,wxPython应用程序将不能运行。
顶级窗口通常用于管理最重要的数据,控制并呈现给用户。这2个基础对象和应用程序的其他部分之前的关系,如图所示。
在图中,这个应用程序对象拥有顶级窗口和主循环时间。顶级窗口管理其窗口中的组件和其他分配给它的数据对象。窗口和她的组件触发的时间基于用户的动作,并接受事件通知以便于改变现实。
1、创建一个wx.App的子类
在创建应用程序之前,先来创建一个没有任何功能的子类。创建和使用一个wx.App子类,需要执行4个步骤
a:定义这个子类
b:在定义的子类中写一个OnInit()初始化方法
c:在程序的主要部分创建这个类的一个实例。
d:调用应用程序实例MainLoop()方法。这个方法将程序的控制权转交给wxPython.
创建一个没有任何功能的子类。具体代码如下:
import wx#导入wxPython class App(wx.App): #初始化方法 def OnInit(self): frame = wx.Frame(parent = None,title = 'hello wyPython') #创建窗口,因为是主窗口,所以他的父类为None title:窗口标题 frame.Show()#显示窗口 return True #返回值 if __name__ == '__main__': app = App()#创建App类实例 app.mainloop()#调用App类的MainLoop()主循环方法
上述代码中,定义了一个子类App().他冀衡父类wx.App.子类中包含一个初始方法OnInit().
在主程序中创建类的实例。然后再调用MainLoop()主循环方法。运行结果如图所示
2、直接使用wx.App
通常,如果在系统中只有一个窗口的话,可以不创建wx.App子类。直接使用wx.App.这个类提供了一个最基本的OnInit()初始化方法。具体代码如下
import wx app = wx.App() frame = wx.Frame(None,title = "hello world") frame.Show() app.MainLoop()
3、使用wx.Frame框架
在GUI中框架通常也称为窗口,框架是一个容器,用户可以将在屏幕上任意移动。并可对他进行缩放,他通常包含标题栏,菜单等。在wxPython中,wx.Frame是所有框架的父类。当你创建wx.Fame的子类时,子类应该调用其父类的构造器wx.Frame.__init__().wx.Frame构造器的语法格式如下:
wx.Frame(parent,id=1,title="“,pos = wx.DefaultPosition,size=wx.DefaultSize,style=wx.DEFAULT_FRAME_STYLE,name="frame")
参数说明:
parent:框架的父窗口。如果是顶级窗口,这个是None。
id:关于新窗口的wxPython ID号。通常设为-1,让wxPython自动生成一个新的ID.
title:窗口的标题
pos:一个wx.Point对象,他指定这个窗口的左上角在屏幕中的位置。在图形用户界面程序中。通常(0,0)是显示器的左上角。这个默认值(-1,-1)将让系统决定窗口的位置。
size:一个wx.Size对象,他指定这个窗口的初始尺寸。这个默认值(-1,-1)将让系统决定窗口的初始尺寸。
style:指定窗口类型的常量。可以使用或运算来组合他们。
name:框架内的名字。可以使用它来寻找这个窗口。
创建wx.Frame子类的代码如下:
import wx class MyFrame(wx.Frame): def __init__(self,parent,id): wx.Frame.__init__(self,parent,id,title="创建Frame",pos=(100,100),size=(300,300)) if __name__ == "__main__": app = wx.App()#初始化应用 frame = MyFrame(parent = None,id= 1)#实例MyFrame类,并传递参数。 frame.Show()#显示窗口 app.MainLoop()#调用MainLoop方法
上述代码中,在主程序中调用MyFrame类,并且传递2个参数。在MyFrame类中,自动执行__init__()初始化方法。接受参数。然后调用父类wx.Frame的__init__()初始方法。设置顶级窗口的相关属性。运行结果如图所示
三、常用控件
创建完窗口以后,我们可以在窗口添加一些控件,所谓的控件,就是经常使用的按钮、文本、输入框,单选框等。
1、StaticText文本类
对于所有的UI工具来说,最基本的任务就是在屏幕上绘制纯文本,在wx.Python中,可以使用wx.StatiText类来完成。使用wx.StaticText能够改变文本的对齐方式,字体和颜色等。wx.StaticText类的构造语法如下:
wx.StaticText(parent,id,label,pos = wx.DefaultPosition,size=wx.DefaultSize,style=wx.DEFAULT_FRAME_STYLE,name="frame")
参数说明:
parent:框架的父窗口。
id:标识符。使用-1可以自动创建一个唯一的标识
label:显示在静态控件中的文本内容。
pos:一个wx.Point对象或者一个python元组。他是窗口部件的位置
size:一个wx.Size对象或者一个python元组。他是窗口部件的尺寸
style:样式标记
name:对象的名字
实例01:使用wx.StaticText输出python之禅.
import wx class MyFrame(wx.Frame): def __init__(self,parent,id): wx.Frame.__init__(self,parent,id,title='创建StaticText类', pos = (100,100),size = (600,400)) panel= wx.Panel(self) #创建画板 #创建标题,并设置字体 title = wx.StaticText(panel,label="Python之禅",pos = (100,20)) font = wx.Font(16,wx.DEFAULT,wx.FONTSTYLE_NORMAL,wx.NORMAL) title.SetFont(font) #创建文本 wx.StaticText(panel,label = "优美胜于丑陋",pos = (50,50)) wx.StaticText(panel,label="明了胜于晦涩", pos = (50, 70)) wx.StaticText(panel, label="简洁胜于复杂", pos=(50, 90)) wx.StaticText(panel, label="复杂胜于凌乱", pos=(50, 110)) wx.StaticText(panel, label="扁平胜于嵌套", pos=(50, 130)) wx.StaticText(panel,label="间隔胜于紧凑", pos = (50, 150)) wx.StaticText(panel, label="可读性很重要", pos=(50, 170)) wx.StaticText(panel, label="即便假借特例的实用性之名,也不可违背这些规则", pos=(50, 190)) wx.StaticText(panel, label="不要包容所有错误,除非你确定需要这样做", pos=(50, 210)) wx.StaticText(panel, label="当存在多种可能,不要尝试去猜测", pos=(50, 230)) wx.StaticText(panel, label="尽量找一种,最好是唯一一种明显的解决方案", pos=(50, 250)) wx.StaticText(panel, label="虽然这并不容易,因为你不是 Python 之父", pos=(50, 270)) wx.StaticText(panel, label="做也许好过不做,但不假思索就动手还不如不做", pos=(50, 290)) wx.StaticText(panel, label="如果你无法向人描述你的方案,那肯定不是一个好方案;反之亦然", pos=(50, 310)) wx.StaticText(panel, label="命名空间是一种绝妙的理念,我们应当多加利用", pos=(50, 330)) if __name__ == "__main__": app = wx.App() frame = MyFrame(parent=None,id = -1) frame.Show() app.MainLoop()
上述代码中,使用panel = wx.Panel(self)来创建画板,并将panel作为父类,然后将组建放入窗体中,此外,使用wx.Font类来设置字体创建一个字体实例,需要使用如下的构造函数:
wx.Font(pointSize,family,style,weight,underline=False,faceName="",encoding = wx.FONTENCODING_DEFFAULT)
pointSize:字体的整数尺寸,单位为磅。
family:用于快速指定一个字体而不需要知道实际字体的名字。
style:指字体是否倾斜。
weight:指字体的醒目程度。
underline:在windows系统下生效,如果取值为true,则是加下划线,False则无下划线。
faceName:指定字体名。
encoding= 允许在几个编码中选择一个,大多数情况可以使用默认编码。
运行结果如图
2 、TextCtrl输入文本类
wx.StaticText类智能够用于显示纯粹的静态文本,但是有时候要输入文本与用户进行交互,此时就需要使用wx.TextCtrl类,它允许输入单行和多行文本,他可以做为密码输入控件。
wx.TextCtrl类的构造函数语法格式如下:
wx.TextCtrl(parent,id,value = " ",pos = wx.DefaulPosition,size = wx.DefaultSize,style= 0,validator =wx.DefaultValidator name =wx.textCtrlNameStr)
参数说明:
style:单行wxTextCtrl样式,取值说明如下:
wx.TE_CENTER:控制中的文本居中。
wx.TE_LEFT:控件中的文本左对齐
wx.TE_NOHIDESEL:文本始终高亮显示,只适用于windows.
wx.TE._PASSWORD:不显示所键入的文本,以星号(*)代替显示。
wx.TE_PROCESS_ENTER:如果使用该参数,那么当用户在空间内按下 回车 时,一个文本输入时间将会触发。否则按键时间由该文本控件或对话框管理
wx.TE_PROCESS_TAB:如果指定了这个样式,那么通常的字符串事件在按下 【TAB】键时创建(一般以为一个制表符将会被插入文本),否则tab由对话框来管 理,通常指控件之间的切换
wx.TE_READONLY:文本控件为只读,用户不能修改其中的文本。
wx.TE_RIGHT:控件中的文本左右对齐。
value:显示该控件中的初始文本。
validator:常用于过滤数据以确保只能键入要接受的数据。
实例2,使用一个wx.TextCtrl类和wx.StaticText类实现一个包含用户名和密码的登录界面。
import wx class MyFrame(wx.Frame): def __init__(self,parent,id): wx.Frame.__init__(self,parent,id,title="创建TextCtrl类", size = (400,300)) panel = wx.Panel(self) self.title = wx.StaticText(panel,label="请输入用户名和密码",pos = (140,20)) self.label_user = wx.StaticText(panel,label="用户名:",pos=(50,50)) self.text_user = wx.TextCtrl(panel,pos = (100,50),size=(235,25),style = wx.TE_LEFT) self.label_pwd = wx.StaticText(panel,pos = (50,90),label= "密 码") self.text_password = wx.TextCtrl(panel,pos = (100,90),size = (235,25),style = wx.TE_PASSWORD)if __name__== "__main__": app = wx.App() frame = MyFrame(parent=None, id=-1) frame.Show() app.MainLoop()
上述代码中,使用wx.TextCtrl类生成用户名,并且设置控件中的文本左对齐。使用wx.TextCtrl类,生成密码。并且设置文本用型号代替。执行效果如图
3、Button按钮类
按钮是GUI界面应用最为广泛的控件,他常用语捕获用户生成的单机时间,最明显的用途是触发绑定到一个处理函数,wxPython类库提供不同类型的按钮,其中最常用的是wx.Button类。
实例3,在实例2的基础上加上【确认】和【取消】按钮
import wx class MyFrame(wx.Frame): def __init__(self,parent,id): wx.Frame.__init__(self,parent,id,title="创建TextCtrl类", size = (400,300)) panel = wx.Panel(self) self.title = wx.StaticText(panel,label="请输入用户名和密码",pos = (140,20)) self.label_user = wx.StaticText(panel,label="用户名:",pos=(50,50)) self.text_user = wx.TextCtrl(panel,pos = (100,50),size=(235,25),style = wx.TE_LEFT) self.label_pwd = wx.StaticText(panel,pos = (50,90),label= "密 码") self.text_password = wx.TextCtrl(panel,pos = (100,90),size = (235,25),style = wx.TE_PASSWORD) self.bt_confirm = wx.Button(panel,label="确定",pos=(105,130)) self.bt_cancel = wx.Button(panel,label = "取消",pos = (195,130)) if __name__== "__main__": app = wx.App() frame = MyFrame(parent=None, id=-1) frame.Show() app.MainLoop()
四、BoxSizer布局
在前面的实例中,使用了文本和按钮等空间并将这些空间通过pos参数布置在pannel面板上。虽然这种设置坐标的方式很容易理解,但是过程很麻烦,此外空间的几核位置是绝对位置,也就是固定道德。当调整窗口大小时,界面会不美观。在wxPython中有一种更智能的布局方式-sizer(尺寸器)。sizer是用户自动布局一组窗口空间的算法。sizer被附加到一个容器,通常是一个框架或者面板。在父容器中,创建的子窗口空间必须被分别添加到sizer。当sizer被附加到容器时,它随后就可以管理它所包含的子布局。
wxPython提供了5个sizer.
(1)使用BoxSizer布局
从尺寸器会管理组件的尺寸。只要将部件添加到尺寸器上,再添加一些布局参数,就可以让尺寸器自己去管理父组件的尺寸。下面使用BoxSize实现简单的布局。代码如下:
import wx class MyFrame(wx.Frame): def __init__(self,parent,id): wx.Frame.__init__(self,parent,id,"用户名登录",size = (400,300)) panel = wx.Panel(self) self.title = wx.StaticText(panel,label = "请输入用户名和密码") #添加容器,容器中控件按纵向排列 vsizer = wx.BoxSizer(wx.VERTICAL) vsizer.Add(self.title,proportion = 0,flag = wx.BOTTOM|wx.TOP|wx.ALIGN_CENTER,border = 15) panel.SetSizer(vsizer) if __name__ == "__main__": app = wx.App() frame = MyFrame(parent=None,id = -1) frame.Show() app.MainLoop()
执行结果如图
上述代码中,首先设置了增加背景控件(wx.Panel),并创建了一个wx.BoxSizer,它带一个决定其水平还是垂直的参数(wx.HORIZONTAL或者wxVERTICAL),默认为水平;然后用Add方法将孔家加入到sizer;最后使用面板SetSizer()方法设定他的尺寸器。
Add()方法的语法格式如下;
Box.add(control,proportion,flag,border)
参数说明:
control:要添加的控件。
proportion:所添加控件在定义的方式所代表方向向上占据的空间比例。如果有如3个按钮,他们的比例值分别为0,1,2,他们都已经天追到一个宽度为30的水平排列wx.BoxSizer,起始宽度都是10,当sizer的宽度从30变成60时,按钮1的宽度保持不变,任然是10,按钮2的苦读约为(10+(60-30)*1/(1+2))=30,按钮2约为20.
flag:flag参数与border参数结合使用可以指定边距宽度,包括以下选项:
wx.LEFT:左边距
wx.RIGHT:右边距
wx.BOTTOM:底边距
wx.TOP:上边距
wx.ALL:上下左右4个边距
可以通过竖线“|”操作符,来联合使用这些标志,此flag参数还可以与proportion是参数结合,指定控件本身的对齐(排列)方式,包括以下选项:
wx.ALIGN_LEFT:左边对齐
wx.ALIGN_RIGHT:右边对齐
wx.ALIGN_TOP:顶部对齐
wx.ALLGN_BOTTOM:底边对齐
wx.ALGN_CENTER_VERTICAL:处置对齐
wx.ALIGN_CENTER_HORIZONTAL:水平对齐
wx.ALIGN_CENTER:居中对齐
wx.EXPAND:所添加控件将占有sizer定位方向上所有可用的控件
boder:控制所添加控件的边距,就是在部件之间添加一些像素的空白。
实例4,使用BoxSizer布局方式,实现实例3道德界面布局效果。具体代码如下:
# 导入wxPython import wx class MyFrame(wx.Frame): def __init__(self, parent, id): wx.Frame.__init__(self, parent, id, "用户登录", size=(400, 300)) panel = wx.Panel(self)# 创建面板 # 创建文本,左对齐 self.title = wx.StaticText(panel, label="请输入用户名和密码 ")#设置控件名称 self.label_user = wx.StaticText(panel, label="用户名:") self.text_user = wx.TextCtrl(panel, style=wx.TE_LEFT)#输入框 self.label_pwd = wx.StaticText(panel, label="密 码:") self.text_password = wx.TextCtrl(panel, style=wx.TE_PASSWORD)#输入框 # 创建“确定”,“取消”按钮并 绑定事件 self.bt_confirm = wx.Button(panel, label="确定") self.bt_canel = wx.Button(panel, label=" 取消") # 创建布局 添加容器,容器中控件横向排列 hsizer_user = wx.BoxSizer(wx.HORIZONTAL) hsizer_user.Add(self.label_user, proportion=0, flag=wx.ALL, border=5)#文本的[用户名占比] hsizer_user.Add(self.text_user, proportion=1, flag=wx.ALL, border=5)#[用户名输入框占比] #因为是用户名和用户名的输入框是在一行,所以设置用1个容器来设置,以下都一样 hsizer_pwd = wx.BoxSizer(wx.HORIZONTAL) hsizer_pwd.Add(self.label_pwd, proportion=0, flag=wx.ALL, border=5)#文本的[密码占比] hsizer_pwd.Add(self.text_password, proportion=1, flag=wx.ALL, border=5)#[密码输入框占比] hsizer_button = wx.BoxSizer(wx.HORIZONTAL) hsizer_button.Add(self.bt_confirm, proportion=0, flag=wx.ALIGN_CENTRE, border=5)#按钮确认占比 hsizer_button.Add(self.bt_canel, proportion=0, flag=wx.ALIGN_CENTRE, border=5)#按钮取消占比 # 添加容器,容器中的控件纵向排列 vsizer_all = wx.BoxSizer(wx.VERTICAL) vsizer_all.Add(self.title, proportion=0, flag=wx.BOTTOM | wx.TOP | wx.ALIGN_CENTRE, border=15) #title是单独的,所以在横向没设置容器 vsizer_all.Add(hsizer_user, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=45) vsizer_all.Add(hsizer_pwd, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=45) vsizer_all.Add(hsizer_button, proportion=0, flag=wx.ALIGN_CENTRE | wx.TOP | wx.RIGHT, border=15) panel.SetSizer(vsizer_all) #备注因为是竖向排列只有1个容器,横向的话有3个容器 if __name__ == "__main__": app = wx.App() frame = MyFrame(parent=None, id=-1) frame.Show() app.MainLoop()
在上述代码中,首先创建按钮和文本控件,然后将其添加到容器中,并且设置横向排列接着设置纵向排列。在蒲剧过程中,通过设置控件的flag和border参数,实现控件位置间的布局。运行结果和实例3的类似。
五、绑定事件
当发生一个事件时,需要让程序注意这些事件并作出反应。这时可以将函数绑定到所涉及事件可能的控件上,当事件发生时,函数就会被调用利用控件Bind()方法将事件处理处理函数绑定到给定的事件上。例如为【确定】按钮加一个单机事件,代码如下。
bt_confirm.Bind(wx.EVT_BUTTON,OnclickSubmit)
参数说明:
wx.EVT_BUTTON:事件类型为按钮箱,在wxPython中有很多wx.EVT_开头的事件类型,例如,类型wx.EVT_MOTION产生移动鼠标,类型wx.ENTER_WINDOW和wx.LEAVE_WINDOW产生当鼠标进入或者离开一个窗口空间,类型wx.EVT_MOUSEWHEEL被绑定到鼠标滚轮的活动
OnclickSunbmit:方法名,事件发生立即执行的方法。
实例5,在实例4的基础上,分别为“确定”,“取消”按钮添加单机事件当用户输入用户名密码后,单机“确定”按钮,如果输入的用户名为“sjc”且密码为“xfd”.则弹出对话框提示“登陆成功”,否则提供“用户名密码不匹配”。当用户单机“取消”按钮时,清空用户输入的用户名密码。
# 导入wxPython import wx class MyFrame(wx.Frame): def __init__(self, parent, id): wx.Frame.__init__(self, parent, id, "用户登录", size=(400, 300)) panel = wx.Panel(self)# 创建面板 # 创建文本,左对齐 self.title = wx.StaticText(panel, label="请输入用户名和密码 ")#设置控件名称 self.label_user = wx.StaticText(panel, label="用户名:") self.text_user = wx.TextCtrl(panel, style=wx.TE_LEFT)#输入框 self.label_pwd = wx.StaticText(panel, label="密 码:") self.text_password = wx.TextCtrl(panel, style=wx.TE_PASSWORD)#输入框 # 创建“确定”,“取消”按钮并 绑定事件 self.bt_confirm = wx.Button(panel, label="确定") self.bt_confirm.Bind(wx.EVT_BUTTON,self.OnclickSunbmit) self.bt_canel = wx.Button(panel, label=" 取消") self.bt_canel.Bind(wx.EVT_BUTTON, self.OnclickCancel) # 创建布局 添加容器,容器中控件横向排列 hsizer_user = wx.BoxSizer(wx.HORIZONTAL) hsizer_user.Add(self.label_user, proportion=0, flag=wx.ALL, border=5)#文本的[用户名占比] hsizer_user.Add(self.text_user, proportion=1, flag=wx.ALL, border=5)#[用户名输入框占比] #因为是用户名和用户名的输入框是在一行,所以设置用1个容器来设置,以下都一样 hsizer_pwd = wx.BoxSizer(wx.HORIZONTAL) hsizer_pwd.Add(self.label_pwd, proportion=0, flag=wx.ALL, border=5)#文本的[密码占比] hsizer_pwd.Add(self.text_password, proportion=1, flag=wx.ALL, border=5)#[密码输入框占比] hsizer_button = wx.BoxSizer(wx.HORIZONTAL) hsizer_button.Add(self.bt_confirm, proportion=0, flag=wx.ALIGN_CENTRE, border=5)#按钮确认占比 hsizer_button.Add(self.bt_canel, proportion=0, flag=wx.ALIGN_CENTRE, border=5)#按钮取消占比 # 添加容器,容器中的控件纵向排列 vsizer_all = wx.BoxSizer(wx.VERTICAL) vsizer_all.Add(self.title, proportion=0, flag=wx.BOTTOM | wx.TOP | wx.ALIGN_CENTRE, border=15) #title是单独的,所以在横向没设置容器 vsizer_all.Add(hsizer_user, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=45) vsizer_all.Add(hsizer_pwd, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=45) vsizer_all.Add(hsizer_button, proportion=0, flag=wx.ALIGN_CENTRE | wx.TOP | wx.RIGHT, border=15) panel.SetSizer(vsizer_all) #备注因为是竖向排列只有1个容器,横向的话有3个容器 def OnclickSunbmit(self, event): message = "" username = self.text_user.GetValue() password = self.text_password.GetValue() if username == "" or password == "": message = "用户名密码不能为空" elif username == "sjc" and password == "xfd": message = "登陆成功" else: message = "用户名密码不匹配" wx.MessageBox(message) def OnclickCancel(self,event): self.text_user.SetValue("")#清空用户名 self.text_password.SetValue("")#清空密码 if __name__ == "__main__": app = wx.App() frame = MyFrame(parent=None, id=-1) frame.Show() app.MainLoop()
在商户代码中,分别使用bind()函数为bt.confirm和bt_cancel绑定了单机事件。运行结果如图所示