概述
了解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()