《Python编程》第七章:图形化用户界面(tkinter)初识

    技术2022-07-13  78

    概述

    了解Python/tkinter的编码基础,主要使用一些简单的组件,包含:如何更好的创建组件、修改属性、pack、以及组件回调函数等;

    tkinter程序的共同步骤:

    1.从tkinter模块中加载一个/多个组件类

    2.创建该组件类的实例为标签类

    3.在父组件中打包新标签

    4.调用主循环,显示窗口,同时开始tkinter的事件循环;

    mainloop方法最后执行,将标签显示在屏幕,进入tkinter等待状态,准备响应用户发起的GUI事件。mainloop函数中,tkinter内部会监控这些事件,如键盘活动、鼠标单击等;

    子组件如何部署在父组件?

    举例:Label(None,text='Hello GUI world !!!').pack();

    第一个参数是父组件对象,即:我们希望将新标签设置于其中。None,表示将新标签设置在该程序的默认顶层窗口;

    第二个参数是标签配置选项。大多数组件的构造函数都能够接受多个关键字参数,对组件的颜色、尺寸、回调函数等进行具体设置

    一、组件尺寸、标题修改及回调函数

    1.组件尺寸、标题、无参数的回调函数

    ''' expand=YES:可以让组件居中,并显示在扩展的空间中 fill选项:可用来拉伸组件,使其充满分配的空间; fill=BOTH,xy轴都拉伸;fill=X:仅水平轴拉伸;fill=Y:仅垂直轴拉伸 ''' from tkinter import * def msg(): print("你很漂亮……") root = Tk() widget = Label(root,text='Hello GUI world!!!') # widget.config(text='Hello GUI world!!!')#config方法,可以在组件创建后的任何时间被调用。 widget.pack(side=TOP,expand=YES,fill=BOTH) #command=函数名,不要带括号,带上括号直接就运行了,不带括号只是调用,要等到触发才运行; widget1 = Button(root,text='打印',command=msg) widget1.pack() #标题设置 root.title('gui1g.py') root.mainloop()

    2.带参数的回调函数

    无参数的回调函数,组件在生成时,直接将command=函数名,即可成功实现回调函数;但是如果函数有参数,应该如何传参喃?要指导回调函数是不能直接加括号的,加括号就直接运行了,不会等待你触发事件才执行。

    方式1:lambda匿名函数实现延迟调用

    from tkinter import * #lambda匿名函数实现延迟调用 def handler(A,B): print(A,B) sys.exit() X=42 Button(None,text='HI',command=(lambda :handler(X,"spam"))).pack() mainloop()

    方式2:对象引用实现延迟调用

    from tkinter import * #对象引用实现延迟调用 def handler(A,B): print(A, B) sys.exit() X=42 def func(): #调用要实现的函数 handler(X,'spam') #command=中间函数 Button(None,text='HI',command=func).pack() mainloop()

    二、用类实现组件的生成

    这个代码是下面两个例子的基础:

    # -*-coding:utf-8-*- #-*-md10_用类实现复用GUI部件.py-*- from tkinter import * class Hello(Frame): def __init__(self,parent=None): Frame.__init__(self,parent) self.pack() self.data = 42 self.make_widgets() def make_widgets(self): #self即Hello本身,继承了Frame widget = Button(self,text='Hello frame world!',command=self.message) widget.pack(side=TOP) widget1 = Button(self,text='关闭',command=self.quit) widget1.pack(side=BOTTOM) def message(self): self.data += 1 print('Hello frame world %s!'%self.data) if __name__ == '__main__': Hello().mainloop()

    下面的 代码引用上一个文件的类,实现模块化。

    # -*-coding:utf-8-*- from tkinter import * from md10_用类复用GUI部件 import Hello class HelloContainor(Frame): def __init__(self,parent=None): Frame.__init__(self,parent) self.pack() self.makeWidgets() def makeWidgets(self): #将上一个py文件中Hello类实现的组件一起添加打包到Frame上,实现模块化 Hello(self).pack(side=RIGHT) Button(self,text='Attach',command=self.quit).pack(side=LEFT) if __name__ == '__main__': HelloContainor().mainloop()

    引用父类的函数实现组件部署,调用的却是子类本身的回调函数:

    ''' 扩展类部件 ''' from tkinter import * from md10_用类复用GUI部件 import Hello class HelloExtender(Hello): def make_widgets(self): Hello.make_widgets(self) Button(self,text='Extend',command=self.quit).pack(side=RIGHT) def message(self): print('Hello',self.data) if __name__ == '__main__': HelloExtender().mainloop()

    三、事件绑定

    # -*-coding:utf-8-*- import sys from tkinter import * def hello(event): print('Press twice to exit!!') def quit(event): print('Hello,I must be going……') sys.exit() widget = Button(None,text='Hello event world!!!') widget.pack() widget.bind('<Button-1>',hello)#鼠标左键1下触发hello widget.bind('<Double-1>',quit)#鼠标左键2下触发quit widget.mainloop()

    四、独立的容器类

    上面使用类完成组件的一些列过程,但是类本身都是基础了tkinter组件类的,即:类的实例对象就是一个组件,可以直接mainloop运行的;下面代码使用思维:类本身不是组件,没有基础tkinter任何组件类,而在类里面去实现组件的一些列过程。即:类的实例不能直接mainloop运行

    # -*-coding:utf-8-*- from tkinter import * class HelloPackage: def __init__(self,parent=None): self.top = Frame(parent) self.top.pack() self.data = 0 self.make_widgets() def make_widgets(self): Button(self.top,text='Bye',command=self.top.quit).pack(side=LEFT) Button(self.top,text='Hye',command=self.message).pack(side=RIGHT) def message(self): self.data +=1 print('Hello number',self.data) if __name__ == '__main__': # 所有的组件都在Frame上,而HelloPackage并不是组件,只是一个类(用来存储真实组件对象及信息); # 所有的组件依附于self.top,若我们要启动GUI,就需要self.top.mainloop();而不是self.mainloop() HelloPackage().top.mainloop()

    对上面独立的容器类的引用:

    from tkinter import * from md14_独立的容器类 import HelloPackage frm = Frame() frm.pack() Label(frm,text='hello').pack() part = HelloPackage(frm) part.top.pack(side=RIGHT)#注意:这里必须要一个top,因为HelloPackage类只是一个容器类,所有组件依附于self.top frm.mainloop()

    比较完美的解决方式是:通过定义方法将获取的不明属性引导至内嵌至的Frame;

    步骤1:创建一个获取类属性的中间类

    #引用上面的py文件 from md14_独立的容器类 import HelloPackage from tkinter import * class HelloPackage(HelloPackage): def __getattr__(self, item): return getattr(self.top,item)#完成并传递到一个实际的组件

    步骤2:再引用上面的类

    from tkinter import * from md15_config import HelloPackage frm = Frame() frm.pack() Label(frm,text='hello').pack() part = HelloPackage(frm) part.pack(side=RIGHT) frm.mainloop()

     

    Processed: 0.027, SQL: 9