常用的GUI框架之wxPython框架

1、初识GUI

1.1、什么是GUI

GUI是Graphical User Interface(图像用户界面)的缩写。在GUI中有输入文本、返回文本,具有有窗口、按钮等图像,也可以通过键盘和鼠标操作。GUI是一种与程序不同的方式。GUI的程序有3个基本要素:输入、处理、输出。

1.2、常用的GUI框架

python的GUI开发,有很多工具包,下面是一些流行的工具包

工具包 描述
wxPython wxpython是python中的一套优秀的GUI图像库,允许python程序员很方便的程序完整的、功能健全的GUI用户界面
Kivy 是一个开源的工具包,能够让相同的源代码创建的程序跨平台运行,主要关注程序型用户界面的开发,如多点触摸应用程序
Flexx Flexx是一个纯python工具包,用来创建图形化应用程序。其使用web技术进行界面的渲染
PyQt PyQt是Qt库的python版本,支持跨平台
Tkinter Tkinter(也叫Tk接口)是Tk图形用户界面工具包标准的Python接口,是一个轻量级的跨平台图像用户界面(GUI)开放工具
Pywin32 Pywin32允许你以像VC一样的形式来使用Python开放win32应用
PyGTK PyGTK让用Python轻松创建具有图形用户界面的程序
pyui4win pyui4win是一个开源的采用自绘技术的界面库

每个工具包都有各自的特点,工具包的选择决定于你的应用常景。

2、wxPython框架的使用

要使用wxPython模块(工具包),得先安装该模块,使用下面命令安装(在命令行操作)

pip install -U wxPython

2.1、创建一个wx.App的子类

在开始创建应用程序之前,要先创建一个没有任何功能的子类。
创建和使用wx.App子类要4个步骤
1、定义这个子类
2、在定义的子类中写一个OnInit()初始化方法
3、在程序的主要部分创建这个类的一个实例
4、调用应用程序实例的MainLoop()方法,这个方法将出现的控制器转给wxPython.

创建一个没有任何功能的子类具体代码如下

import wx   # 导入wxpython
class App(wx.App):
    # 初始化方法
    def OnInit(self):
        frame = wx.Frame(parent=None, title= "Hello wxPython")     # 创建窗口用
        frame.Show()  # 显示窗口
        return True  # 返回值

if __name__ == '__main__':
    app = App()     # 创建APP类的实例
    app.MainLoop()  # 调用App类的MainLoop()主循环方法

上述代码中,定义了子类App,它继承了父类wx.App

2.2、直接使用wx.App

如果在系统中只有一个窗口,通过不创建wx.App的子类,直接使用wx.App,这个类提供了一个最基本的OnInit()初始化方法,代码如下

import wx   # 导入wxPython
app = wx.App()  # 初始化wx.App类
frame = wx.Frame(None, title='Hello World')  # 定义一个顶级窗口(NOne就是表示顶级窗口)
frame.Show()   # 显示窗口
app.MainLoop()  # 调用wx.App类中的MainLoop()主循环方法

2.3、使用wx.Frame框架

在GUI中框架通过称为窗口。框架是一个容器,用户可以将它在屏幕上任意移动,并进行缩放,它通常包含标题栏、菜单栏等。在wxPython中,wxFrame是所有框架的父类。当创建wx.Frame的子类时,子类应该调用其父类的构造器wx.Frame.__int__()。wx.Frame的构造器语法格式如下:

wx.Frame(parent, id= -1,title="",pos =wx.DefaultPosition,size=wx.DefaultSize,style=wx.DEFAULT_FRAME_STYLE,name="frame")

参数说明
1、parent: 框架的父类窗口。如果是顶级窗口,这个值为None
2、id: 关于新窗口的wxPython ID号。通常设为-1,让wxPython自动生成一个新的ID。
3、title: 窗口的标题
4、pos: 一个wx.Point对象,它指定这个新窗口的左上角在屏幕中间的位置。在GUI程序中,通过(0,0)是显示器的左上角。这个默认的(-1,-1)将让系统决定窗口的位置。
5、size: 一个wx.Size对象,它指定这个窗口的初始尺寸。这个默认的(-1,-1)将让系统决定窗口的初始尺寸
6、style: 指定窗口类型的常量。可以使用或运算来组合它们
7、name: 框架的内在的名字可以使用它来需找这个窗口。

创建wx.Frame子类的代码如下

import wx   # 导入wxPython
class MyFrame(wx.Frame):
    def __init__(self, parent, id):
        wx.Frame.__init__(self, parent, id, title="创建Frame", pos=(100,100), size=(500,300))
if __name__=='__main__':
    app = wx.App()                       # 初始化应用
    frame = MyFrame(parent=None, id=-1)  # 实例MyFrame并传入参数
    frame.Show()       # 显示窗口
    app.MainLoop()     # 调用MainLoop()主循环方法

2.4、常用的控件

控件就是我们在创建完窗口以后,在窗口添加的按钮、文本、输入框等等。

2.41、StaticText文本类

对于所有的UI(用户界面)工具来说,最基本的任务就是在屏幕上绘制文本。在wxPython中,可以使用wx.StaticText类来完成。使用wx.StaticText能够改变文本的对齐方式、字体。颜色等。
wx.StaticText的构造函数语法格式

wx.StaticText(parent,id,label,pos=wx.DefaultPosition,size=wx.DefaultSize,style=0,name="staticText")

参数说明
parent:父窗口部件
id:标识符。使用-1可以自动创建一个唯一的标识
label:x显示在静态控件中的文本内容
pos:一个wx.Point或一个Python元组,它就是窗口部件的位置。
size:一个wx.Point或一个Python元组,它就是窗口部件的尺寸。
style:样式标记
name:对象的名字

例子:使用wx。StaticText输出Python之禅(The Zen of Python)
1、在python控制台输入import this之后,会输出一堆英文,就是python之禅
在这里插入图片描述
2、使用StaticText类输出python之禅(The Zen of Python)

import wx   # 导入wxPython


class MyFrame(wx.Frame):
    def __init__(self, parent, id):
        wx.Frame.__init__(self, parent, id, title="创建StaticText类", pos=(100, 100), size=(600, 700))
        panel = wx.Panel(self)   # 创建画板
        # 创建标题,并设置字体
        title = wx.StaticText(panel, label='The Zen of Python————Tim Peters', pos=(100, 20))
        font1 = wx.Font(16, wx.DEFAULT, wx.FONTSTYLE_NORMAL, wx.NORMAL)
        title.SetFont(font1)
        # 创建文本
        wx.StaticText(panel, label='Beautiful is better than ugly.', pos=(50, 50))
        wx.StaticText(panel, label='Explicit is better than implicit.', pos=(50, 70))
        wx.StaticText(panel, label='Simple is better than  complex.', pos=(50, 90))
        wx.StaticText(panel, label='Complex is better than  complicate.', pos=(50, 110))
        wx.StaticText(panel, label='Flat is better than nested.', pos=(50, 130))
        wx.StaticText(panel, label='Sparse is better than dense,', pos=(50, 150))
        wx.StaticText(panel, label='Readability counts', pos=(50, 170))
        wx.StaticText(panel, label='Special cases are not special enough to break rules.', pos=(50, 190))
        wx.StaticText(panel, label='Although practically beats purity.', pos=(50, 210))
        wx.StaticText(panel, label='Errors should never pass silently.', pos=(50, 230))
        wx.StaticText(panel, label='Unless explicitly silenced.', pos=(50, 250))
        wx.StaticText(panel, label='In the face of ambiguity, refuse the temptation to guess.', pos=(50, 270))
        wx.StaticText(panel, label='There should be one-- and preferable only one --obvious way to do it.', pos=(50, 290))
        wx.StaticText(panel, label='Although that way may not be obvious at first unless you are Dutch.', pos=(50, 310))
        wx.StaticText(panel, label='Now is better than never.', pos=(50, 330))
        wx.StaticText(panel, label='Although never is often better than *right* now.', pos=(50, 350))
        wx.StaticText(panel, label='If the implementation is hard to explain, it is a bad idea.', pos=(50, 370))
        wx.StaticText(panel, label='If the implementation is hard to explain, it is a bad idea.', pos=(50, 390))
        wx.StaticText(panel, label='If the implementation is easy to explain, it is may be a good idea.', pos=(50, 410))
        wx.StaticText(panel, label='Namespaces are one honking great idea.', pos=(50, 430))


if __name__=='__main__':
    app = wx.App()                       # 初始化应用
    frame = MyFrame(parent=None, id=-1)  # 实例MyFrame并传入参数
    frame.Show()       # 显示窗口
    app.MainLoop()     # 调用MainLoop()主循环方法

wx.Font构造函数语法

wx.Font(pointSize, family, style, weight, underline=False, faceName="",encoding=wx.FONTENCODING_DEFAULT)

参数说明
pointSize:字体的整数尺寸,单位为磅。
family: 用于快速指定一个字体而无须知道该字体的具体名字。
style: 指明字体的醒目程度
underline:仅仅在Windows系统下有效果,如果值为True,有下画线,False无下画线
faceName:指定字体名
encoding: 允许在几个编码中选择一个,大多数情况下可以使用默认编码

2.42、TextCtrl输入文本类

wx.StaticText类只能用于显示静态的文本,要想输入文件与用户进行交互,要用wx.TextCtrl类,它允许单行和多行文本。它也可以作为密码输入控件,掩饰所按下的按钮。
wx.TextCtrl类的构造函数语法

wx.TextCtrl(parent, id, value="", pos=wx.DefaultPosition, size=wx.DefaultSize, style=0, validator=wx.DefaultValidator,name=wx.TextCtrlNameStr)

参数说明:
其中parent,id,pos,size,style,name与wx.StaticText构造函数相同。

value:显示在该控件中的初始文本
validator:常用于过滤数据,来确保只能输入要接收的数据。

style:单行wx.TextCtrl的样式、取值及说明如下
1、wx.TE_CENTER:控件中的文本居中。
2、wx.TE_LEFT:控件中的文件左对齐。
3、wx.TE_NOHIDESEL:文本始终高亮显示,只适用于windows。
4、wx.TE_PASSWORD: 不显示所输入的文本,以星号代替。
5、wx.TE_PROCESS_ENTER:如果使用该参数,那么当用用户在控件内按下回车键时,一个文本输入事件将被触发。否则,按键事件内在的由该文本控件或该对话框管理。
6、wx.TE_PROCESS_TAP:如果指定了这个样式,那么通常的字符事件在键按下时创建(一般意味着一个制表符将被插入文本)。否则,键由对话框来管理,通常是控件间的切换。
7、wx.TE_READONLY: 只读模式
8、wx.TE_RIGHT:文本右对齐

例子1:用wx.TextCtrl类和wx.StaticText类实现一个包含用户名和密码的登录界面。

import wx   # 导入wxPython


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, label="密 码:", pos=(50, 90))
        self.text_pwd = 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)    # 初始化MyFrame类,并传递参数
    frame.Show()    # 显示窗口
    app.MainLoop()     # 调用主循环方法

2.43、Button按钮类

按钮是GUI界面中应用最为广泛的控件,它常常用于捕获用户生成的单击事件。其最明显的用途是触发绑定到一个处理函数

wx.Python类库提供了不同类型的按钮,其中最为简单、最常用的是wx.Button类。wx.Button的构造函数语法如下:

wx.Button(parent, id, label, pos, size=wxDefaultSize, style=0,validator,name="button")

例子2:在上面的例子1中添加确定和取消按钮

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, label="密 码:", pos=(50, 90))
        self.text_pwd = 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)    # 初始化MyFrame类,并传递参数
    frame.Show()    # 显示窗口
    app.MainLoop()     # 调用主循环方法

2.5、BoxSizer布局

上面的那种使用座标的方法过于麻烦。在wxPython有另一种更智能的布局方式:sizer(尺寸器)。sizer是用于自动布局一组窗口控件的算法。
wxPython提供了5个sizer,如下表

sizer名称 描述
BoxSizer 在一条水平或重垂直窗口部件的布局。控制窗口部件在行为上很灵活。一般用于嵌套的样式,应用面广
GridSizer 一个基础的网格布局,当你要放置的窗口部件是同样的尺寸且整齐地放入一个规则的网格中可以使用它
FlexGridSizer 对GridSizer做了一定改变,窗口部件有不同的尺寸时,可以有更好的结果
GridBagSizer GridSizer系列中最灵活的成员。网络中的窗口部件可以随意放置
StaticBoxSizer 一个标准的BoxSizer,常有标题和环线

2.51、什么是BoxSizer

在一条线上布局子窗口部件。wx.BoxSizer的布局方向可以是水平或坚直的,并且可以在水平或坚直方向上包含子sizer以创建复杂的布局。是wxPython中所提供的最简单。最林华的控件。

2.52、使用BoxSizer

尺寸器会管理组件的尺寸,只有将部件添加上尺寸器,和一些布局参数,就可以让尺寸器去管理父组件的尺寸。下面是使用BoxSizer的例子

import wx   # 导入wxPython

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_CENTRE, border = 15)
        panel.SetSizer(vsizer)


if __name__== '__main__':
    app = wx.App()                        # 初始化
    frame = MyFrame(parent=None, id=-1)   # 实例化MyFrame类,并传递参数
    frame.Show()                          # 显示窗口
    app.MainLoop()                        # 调用主循环方法

Add的方法可以将控件加入sizer中
Add()语法格式

Box.Add(control, proportion, flag, border)

参数说明:
1、control:要添加的控件

2、proportion:所要添加的控件在定义方式所代表方向上,占据的控件比较。如果有3个按钮,他们的比例值分别为0,1,2,他们都以添加到一个宽带为30的水平批量的wx.BoxSizer中,起始宽度都是10.当sizer的宽度有30变到30.按钮1的宽度不变为[10+(60-30)*0/(0+1+2)]=10,按钮2的宽度变为[10+(60-30)*1/(0+1+2)]=20,按钮3的宽度变为[10+(60-30)*2/(0+1+2)]=30,

3、flag:flag参数与border参数结合使用可以知道边距宽度,有以下选项
(1)、wx.LEFT:左边距
(2)、wx.RIGHT:右边距
(3)、wx.BOTTOM:底边距
(4)、wx.TOP:上边距
(5)、wx.ALL:上下左右4个边距
(6)、wx.LEFT:左边距

可以通过竖线操作符联合使用这些标志。flag参数还可以与proportion参数结合,制作控件本身的对齐方式,包以下选项
(1)、wx.ALIGN_LIFT:左边对齐
(2)、wx.ALIGN_RIGHT:右边对齐
(3)、wx.ALIGN_BOTTOM:底边对齐
(4)、wx.ALIGN_CENTER_VERTICAL:垂直对齐
(5)、wx.ALIGN_CENTER_HORIZONTAL:水平对齐
(6)、wx.ALIGN_CENTER:居中对齐
(7)、wx.ALIGN_EXPAND:所添加的控件将占有sizer定位上的所有可用的空间

4、border:控制所有添加空间的边距,就是在空间之间添加一些像素的空白

例子3、使用Boxsizer设置登入界面布局

import wx   # 导入wxPython

class MyFrame(wx.Frame):
    def __init__(self, parent, id):
        wx.Frame.__init__(self, parent, id, '用户登录', size=(400, 300))
        # 创建面板
        panel = wx.Panel(self)

        # 创建“确定”和“取消”按钮,并绑定事件
        self.bt_confirm = wx.Button(panel, label='确定')
        self.bt_cancel = wx.Button(panel, label='取消')
        # 创建文本,左对齐
        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_pwd = wx.TextCtrl(panel, style=wx.TE_PASSWORD)
        # 添加容器,容器中控件横向排列
        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)
        hsizer_pwd = wx.BoxSizer(wx.HORIZONTAL)
        hsizer_pwd.Add(self.label_pwd, proportion=0, flag=wx.ALL, border=5)
        hsizer_pwd.Add(self.text_pwd, 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_cancel, 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)
        vsizer_all.Add(hsizer_user, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.ALIGN_RIGHT, border=45)
        vsizer_all.Add(hsizer_pwd, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.ALIGN_RIGHT, border=45)
        vsizer_all.Add(hsizer_button, proportion=0, flag=wx.ALIGN_CENTRE | wx.TOP, border=15)
        # 设置 面板 panel 的尺寸管理器为 vsizer_all
        panel.SetSizer(vsizer_all)


if __name__ =='__main__':
    app = wx.App()                              # 初始化
    frame = MyFrame(parent=None, id=-1)         # 实例化,并传参
    frame.Show()                                # 显示窗口
    app.MainLoop()  

上面代码中,使用BoxSizer将绝对位置改为相对位置布局。

2.6、事件处理

1、事件就是用户执行的地址,如单击按钮就是一个单击事件。在上面的例子中完成布局后就是输入用户名密码,点击确定按钮就要判读信息是否正确,并输出对应的提示,这就要使用wx.Python的事件处理。

2、而我们通过将函数绑定到事件可以发生的控件上,当事件发生时,函数就被调用。利用控件的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被绑定到鼠标滚轮的活动事件里。

OnlickSubmit:方法名。事件发生时执行该方法。
例子4、使用事件判断用户登录
在例子上的基础上,分别为"确定"和"取消"按钮添加单击事件。输入账号密码后,点击“确定”按钮,如果用户名为wr,且密码为giun,则弹出对话框“登录成功”,否则弹出对话框“用户名和密码不匹配”,点击“取消”按钮时,清空用户名和密码

import wx   # 导入wxPython


class MyFrame(wx.Frame):
    def __init__(self, parent, id):
        wx.Frame.__init__(self, parent, id, '用户登录', size=(400, 300))
        # 创建面板
        panel = wx.Panel(self)

        # 创建“确定”和“取消”按钮并绑定事件
        self.bt_confirm = wx.Button(panel, label='确定')
        self.bt_confirm.Bind(wx.EVT_BUTTON, self.OnclickSubmit)
        self.bt_cancel = wx.Button(panel, label='取消')
        self.bt_cancel.Bind(wx.EVT_BUTTON, self.OnclickCancel)
        # 创建文本,左对齐
        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_pwd = wx.TextCtrl(panel, style=wx.TE_PASSWORD)
        # 添加容器,容器中控件横向排列
        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)
        hsizer_pwd = wx.BoxSizer(wx.HORIZONTAL)
        hsizer_pwd.Add(self.label_pwd, proportion=0, flag=wx.ALL, border=5)
        hsizer_pwd.Add(self.text_pwd, 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_cancel, 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)
        vsizer_all.Add(hsizer_user, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.ALIGN_RIGHT, border=45)
        vsizer_all.Add(hsizer_pwd, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.ALIGN_RIGHT, border=45)
        vsizer_all.Add(hsizer_button, proportion=0, flag=wx.ALIGN_CENTRE | wx.TOP, border=15)
        # 设置 面板 panel 的尺寸管理器为 vsizer_all
        panel.SetSizer(vsizer_all)

    def OnclickSubmit(self, event):
        """ 单击确定按钮,执行方法 """
        message = ""
        username = self.text_user.GetValue()    # 获取输入的用户名
        password = self.text_pwd.GetValue()     # 获取输入的密码
        if username == 'wr' and password == 'giun':
            message = "登录成功"
        else:
            message = "用户名和密码不匹配"
        wx.MessageBox(message)

    def OnclickCancel(self, event):
        """ 单击取消按钮,执行方法 """
        self.text_user.SetValue("")
        self.text_pwd.SetValue("")


if __name__ == '__main__':
    app = wx.App()          # 初始化应用
    frame = MyFrame(parent=None, id=-1)  # 实例化,并传参
    frame.Show()   # 显示窗口
    app.MainLoop()  # 调用主循环方法
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章