Python:初识GUI编程【wxPython】

  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()
Button

四、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绑定了单机事件。运行结果如图所示

   

原文地址:https://www.cnblogs.com/sunjinchao/p/11995402.html