文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Python tkinter(GUI编程)模块最完整教程(上)

2023-08-31 10:21

关注

提示:下滑文章左侧可以查看目录!

1.1 认识tkinter

tkinter是一个GUI开发模块,是Tcl/Tk语言在Python上的接口,可以在大部分操作系统上运行。tkinter非常的简单而且好用。tkinter模块是自带的Python模块,如果在安装Python的时候勾选了Tcl/Tk这个选项,那么使用tkinter不会有任何问题。

导入模块非常简单,但是Python3和Python2略有不同,Python3是这样的:

import tkinter

本文的示例以Python3为准,而Python2是这样的:

import Tkinter #Tkinter开头的t是大写的

不过tkinter这个名字非常长,所以我们通常习惯这么导入:

import tkinter as tkfrom tkinter import *

如果导入时候就出现了错误,提示找不到_tkinter这一模块,或者调用里面的方法时出现版本错误提示,可能是因为安装时不到位,没有勾选Tk/Tcl这一选项。在安装包中选择Modify,更改Python的安装即可

接下来让我们了解一下自己tkinter的版本:

import tkinterprint(tkinter.TkVersion)

 最好是使用8.5 Version以上的tkinter,功能比较全面一些。

1.2 tkinter的坐标系与颜色格式

坐标系

组件的排放,鼠标事件等功能都少不了坐标。tkinter的坐标系和数学上习惯用的坐标系略有不同,和pygame的坐标系是一样的。

以左上角为起点,x轴向右延伸,y轴向下延伸。在窗口中,容器的左上角是(0, 0),不包括窗口的栏和菜单栏。

颜色

当在tkinter中设置颜色时,可以用两种表示颜色的方式:一种是颜色的名称,比如"green", "brown";另一种是颜色的十六进制形式,比如"#00ffff"。遗憾的是,tkinter不支持颜色RGB元组形式,不过可以把它转换成十六进制形式。

这种十六进制形式相当于:"#"+R的十六进制+G的十六进制+B的十六进制。比如(255, 255, 255)是纯白,转换成十六进制形式就变成了#ffffff。

tkinter也有一种特殊的颜色名称,叫做SystemButtonFace,是一种浅灰色,是组件的默认背景颜色。

1.3 创建根窗口

根窗口是最主要的一个窗口,根窗口最好只有一个,因为一个Tk就是一个新的Tcl/Tk解释器,解释器并不需要太多。

根窗口使用tkinter中的Tk方法创建。在窗口中,我们可以添加各种各样的控件,也称组件(widget),比如按钮、文本输入框等,我们将在后期介绍。窗口也可以有一些子窗口。当父窗口关闭后,所有的子窗口会跟着关闭,但是子窗口关闭,父窗口不会关闭。

from tkinter import *root = Tk()mainloop()

这一段代码创建一个窗口,并且循环显示这个窗口。mainloop方法,可以让窗口循环显示,否则运行时窗口一闪就没了。一定不要忘记mainloop!mainloop也可以用while True: root.update()这一段代替,不过mainloop更加常用一些。mainloop也可以作为窗口的一个方法,即root.mainloop()。

这段代码创建了一个独立的窗口,默认叫tk,你可以在下面的任务栏找到它。同样,你也可以自由拖拽它的位置,改变窗口的大小。也可以把它关闭、最小化、最大化。

Tk(screenName=None, baseName=None, className='Tk', useTk=1, sync=0, use=None)

Tk有一个参数叫做className,允许你改变窗口。但是这样改变有一个bug,就是窗口的首字母会自动小写,因此不推荐你这么做,而应使用title方法。Tk的参数并不常用,但有一些比较基础常用的方法,更多的方法,请参见2.2.14

方法使用方法
title(string=None)设置窗口的,同时返回窗口
geometry(newGeometry=None)设置窗口的尺寸大小,同时返回当前窗口尺寸
iconbitmap(bitmap=None)设置窗口的图标,需指定图标文件(*.ico)的位置
resizable(width=None, height=None)设定是否能够改变窗口的宽和高尺寸
destroy()销毁窗口,也就是把窗口关掉

下面看一个示例,演示了tk中一些常用的窗口操作:

from tkinter import *root = Tk()root.title("我的窗口")root.iconbitmap("my_icon.ico")root.geometry("500x500")root.resizable(False, False)mainloop()

 

可以看出,窗口被设置了"我的窗口",图标也变成了自定义的图标。由于resizable的设定,这个窗口无法改变大小,只能保持在500x500。 

下面着重讲一下geometry方法。这个方法不仅可以设置窗口的尺寸,也可以设置窗口在电脑屏幕上的位置。给定参数的格式是:widthxheight+x+y。root.geometry("300x100+20+50")代表的就是把root窗口设置为300x100的尺寸,与屏幕最左边相隔20像素,与屏幕最上方相隔50像素。可以只设置窗口的尺寸,即widthxheight;也可以只设置窗口的位置,即+x+y。geometry还有一些用法,在讲Wm类的时候会介绍。

窗口有一个默认的背景颜色,同样也是大多数tk组件的颜色。这个颜色是一种浅灰色,在tk内部称作SystemButtonFace,只能在tk中使用,其他模块是不支持这个颜色的。如果要改变窗口的背景,可以使用窗口的config方法,也可以写作configure方法。大部分控件都支持这个方法,用来定义控件后改变它的属性。

from tkinter import *root = Tk()root.config(bg="blue")root.mainloop()

一个纯蓝色的窗口就出现了。

1.4 组件

tkinter支持很多组件(又叫控件、小部件等等),可以帮助你完成一些功能。组件根据坐标被排列在容器(container)中,窗口的界面是该窗口中最大的容器。

tkinter的组件有:

 tkinter还有一些子模块,如ttk,messagebox,colorchooser,filedialog等。

ttk中有一些扩展组件,里面有一些和主模块一样的控件,但是样子要不同。ttk有一个最大的特点,组件的字体、颜色等功能不能直接修改,而是要用ttk.Style形式修改,后期会讲述。而tkinter主模块中可以直接指定组件的颜色、字体等样式。所以,如果在from tkinter import *后继续导入from tkinter.ttk import *,就会覆盖tkinter.ttk与tkinter主模块中相同的组件,要改变字体和颜色只能使用Style的形式。这一点千万不能弄错。

tkinter.ttk的扩展组件有:

组件都有一个参数,用来定义这个组件的父容器,大多数组件的类也都有一些共同的参数,这些参数以**kw的形式传递,如:

参数名称作用
master组件的父容器,一般必选
name组件在Tcl/Tk内部的名称

bg

background

改变组件的背景(ttk没有)

fg

foreground

改变组件的前景色,一般是文本颜色
width组件的宽,单位是像素(在文本输入类组件中,单位是字符数量)
height组件的高,单位是像素(在文本输入类组件中,单位是字符数量)
cursor鼠标放上组件的光标样式
relief组件边框样式
state组件状态,可设置为normal(普通样式),disabled(禁用),active(激活),readonly(只读)。其中normal和disabled所有组件都支持,而active,readonly只有部分组件支持。
takefocus组件是否能获取焦点

bd

borderwidth

组件边框的宽度
activebackground组件激活时的背景色
activeforeground组件激活时的前景色
disabledforeground组件禁用时的前景色
disabledbackground组件禁用时的背景色
highlightcolor高亮(组件获得焦点)时的边框颜色
highlightthickness高亮边框宽度
exportselection这个是所有含有输入功能的组件的共有参数,表示选中的内容是否可以被Misc.selection_get方法检测到,参见后文对Misc类的介绍

这意味着,你可以这么定义一个组件:Label(master=root, bg="blue")。组件的类也有一个cnf参数,传给这个参数一个字典,也可以达到定义组件的效果。上面也可以写作:Label(cnf={"master":root, "bg":"blue})。

组件也有一些共同的方法:

方法名称作用
after(ms, func=None)等待ms毫秒后执行一次func
bind(sequence=None, func=None)绑定事件,检测到事件后调用func
unbind(sequence)解除绑定事件
update()刷新组件,一般不需要手动调用
cget(key)返回关键字参数key的值,如:root.cget("bg")返回root的背景色
configure(**kw)也写作config,重新改变组件的关键字参数设置
destroy()销毁组件
focus_set()设置输入焦点

tkinter有一系列的子模块,这里介绍主模块内一些方法的使用方式。

2.1 Label

本节中你将了解tk中最常用也是最简单的组件:标签。

 参考资料:Python Tkinter 标签控件(Label) | 菜鸟教程

 ​​​​​​​

Label(master=None, cnf={}, **kw)

参数名称作用
text显示的文本
font文本的字体
image显示的图片
bitmap显示的位图,和image只能指定一个
textvariable绑定的文本变量
compound当文本和图片同时显示时,图片位于文本的方位,可以是top, bottom, left, right, center,如:设置为top表示图片位于文本上方
padx标签内容与左右的间距
pady标签内容与上下的间距
anchor文本靠标签哪个方向显示,可以是n,s,w,e,ne,nw,sw,se,center,即北、南、西、东、东北、西北、西南、东南、中间,默认靠中间显示
justify文本的对齐方式,可以是left, right, center,默认是center
wraplength自动换行字符数量,到达数量后文本会自动换一行显示

创建Label

from tkinter import *root = Tk()root.geometry("200x200")lab = Label(root, text="Hello, Tkinter!")lab.pack()mainloop()

创建Label的时候,先要指定master,即摆放组件的父容器。所有组件都需要这样,不然tk可能不清楚你要排放在哪个容器上面。text指定显示的文本。这样就定义好了一个Label对象,赋值给lab。lab.pack()的意思是,将定义的Label摆放到父容器上面。所有的组件都需要在定义后摆放到窗口上,不然组件显示不了。至于排放位置的设置,之后会讲述到。

运行效果如下:

 

relief参数

relief参数设定组件的样式,大多数组件都支持relief参数。

from tkinter import *root = Tk()root.geometry("200x200")lab = Label(root, text="Hello, Tkinter!", relief="sunken")lab.pack()mainloop()

运行效果: 

 

 relief参数指定了组件边框的样式,一共有6种relief,分别是flat, groove, raised, ridge, solid, sunken。Label的默认relief是flat。这6种relief的效果如下:

cursor参数

参考资料:【Python cursor指针】——Python Tkinter Cursor鼠标指针属性值

cursor参数指定鼠标移动到组件上时,光标的样子。光标样式有很多,这里不再赘述,可以参考下面这个示例,它会显示光标所有的样式。鼠标放在对应Label上,会显示出当前光标样式。

cursorList = ['arrow', 'xterm', 'watch', 'hand2', 'question_arrow', 'sb_h_double_arrow', 'sb_v_double_arrow', 'fleur',              'crosshair', 'based_arrow_down', 'based_arrow_up', 'boat', 'bogosity', 'top_left_corner',              'top_right_corner', 'bottom_left_corner', 'bottom_right_corner', 'top_side', 'bottom_side', 'top_tee',              'bottom_tee', 'box_spiral', 'center_ptr', 'circle', 'clock', 'coffee_mug', 'cross', 'cross_reverse',              'diamond_cross', 'dot', 'dotbox', 'double_arrow', 'top_left_arrow', 'draft_small', 'draft_large',              'left_ptr', 'right_ptr', 'draped_box', 'exchange', 'gobbler', 'gumby', 'hand1', 'heart', 'icon',              'iron_cross', 'left_side', 'right_side', 'left_tee', 'right_tee', 'leftbutton', 'middlebutton',              'rightbutton', 'll_angle', 'lr_angle', 'man', 'mouse', 'pencil', 'pirate', 'plus', 'rtl_logo', 'sailboat',              'sb_left_arrow', 'sb_right_arrow', 'sb_up_arrow', 'sb_down_arrow', 'shuttle', 'sizing', 'spider',              'spraycan', 'star', 'target', 'tcross', 'trek', 'ul_angle', 'umbrella', 'ur_angle', 'X_cursor']#所有的光标样式from tkinter import *root = Tk()for i in range(len(cursorList)):    cursor = cursorList[i]        Label(text=cursor, cursor=cursor, relief="groove").grid(        column=i // 20, row=i % 20, sticky="we") #后面会讲到grid,是一种排放组件方式root.mainloop()

介绍一下常见的光标样式。不同的主题和系统可能有所不同。

arrow
xterm
watch
hand2
question_arrow
sb_h_double_arrow
sb_v_double_arrow
fleur
crosshair

font参数

font参数指定文本的字体,大多数带有文本的组件都支持这个参数。font参数指定字体的样式、大小、以及是否有加粗下划线等特殊样式。font参数可以是tkinter.font.Font对象,也可以只给一个字体名称或是字体大小数值,或是给一个元组。

lab = Label(root, text="Hello!", font=("黑体", 20)) #字体为黑体,大小20;顺序不能颠倒lab = Label(root, text="Hello!", font=20) #只设置大小20lab = Label(root, text="Hello!", font="黑体") #只设置字体为黑体

字体的元组后面还可以加上字体的特殊样式,一共有bold(加粗), italic(斜体),underline(下划线),overstrike(删除线)几种。可以叠加设置。

Label(root, text="加粗", font=("黑体", 20, "bold")).pack()Label(root, text="斜体", font=("黑体", 20, "italic")).pack()Label(root, text="下划线", font=("黑体", 20, "underline")).pack()Label(root, text="删除线", font=("黑体", 20, "overstrike")).pack()Label(root, text="叠加使用", font=("黑体", 20, "bold", "italic", "underline", "overstrike")).pack()

运行效果:

 

bitmap参数

bitmap参数指定添加位图,即内置图标,有error, info, hourglass, questhead, question, warning, gray12, gray25, gray50, gray75。下面的示例列举了所有bitmap:

from tkinter import *root = Tk()bitmaps = ["error", "info", "hourglass", "questhead", "question", "warning",           "gray12", "gray25", "gray50", "gray75"]for bitmap in bitmaps:    Label(root, text=bitmap, bitmap=bitmap, compound="left").pack()mainloop()

compound的意思是:图片置于文字的位置,上面的参数解释有。

运行效果:

image参数

image参数在Label中添加图片。这个图片是一个tk.PhotoImage对象,支持的格式只有*.gif, *.ppm, *.pgm,较新版的tk支持显示*.png。注意:直接在图片文件后面改后缀不会改变图片本身的文件类型!更需要强调的一点是,图片对象必须要赋值给一个全局变量,或者是类的实例变量之类的,保证不会被Python机制回收,否则图片无法正确显示。

image = tkinter.PhotoImage(file="图片名称")

这段代码建立了一个tk图片对象,现在需要把它传递给Label。

image = PhotoImage(file="monster.gif")Label(root, image=image, text="It's a monster.", compound="top").pack()

运行效果: 

 但是,如果想要显示更多的图片文件格式,比如*.jpg该怎么办呢?这时候需要使用pillow工具。这是一个第三方模块,需要用pip安装:pip install pillow,导入时import PIL。

from tkinter import *from PIL import Image, ImageTkroot = Tk()root.geometry("200x200")image = ImageTk.PhotoImage(Image.open("monster.png"))Label(root, image=image, text="It's a monster.", compound="top").pack()mainloop()

运行效果: 

 这样,我们用PIL工具成功显示了png图片(不过版本较新的Tk本来也可以显示png图片)。也需要注意,在使用tkinter.PhotoImage的时候,需要指定file="文件名"这个关键字参数,但使用PIL工具则不需要指定file关键字参数。

tkinter也有一些内部的图片,可以通过字符串传递给image。

包括:"::tk::icons::error","::tk::icons::information","::tk::icons::question","::tk::icons::warning"。

它们的效果如下:

from tkinter import *root = Tk()for image in ["::tk::icons::error",              "::tk::icons::information",              "::tk::icons::question",              "::tk::icons::warning"]:    Label(root, text=image, image=image, compound="top").pack()mainloop()

这些名字为什么这么复杂呢?其实,::是Tcl语言命名空间的表示方式,这里不多讲。

textvariable参数

tkinter提供了一些变量对象,可以绑定到组件,可以设置它们的值。绑定的组件会随着设置而刷新。这些对象有StringVar()文本变量,IntVar()整数变量,DoubleVar()浮点数变量,BooleanVar()布尔值变量。

建立一个tkinter变量的方法是:

var = tkinter.StringVar()

然后就可以设置变量的值:

var.set(value)

也可以获取变量的值:

sth = var.get()

 StringVar中可以设置文字,IntVar可以设置整数,BooleanVar可以设置True和False,等等。

Label绑定textvariable,只需要添加一个参数textvariable=var,后期如果想要更改Label中的内容,可以执行var.set(value)来更改。当然也可以使用lab.config(text=value)这样的方式。

2.2 Button

Button即按钮,可以绑定一个回调函数,用户点击时将会执行这个函数。

参考资料:Python Tkinter 按钮组件 | 菜鸟教程

 

Button(master=None, cnf={}, **kw)

很多tk组件都有共通性,比如带有文本的组件,大多都有text, font, textvariable这些参数。Button的参数和Label基本类似,也支持text, image, bitmap等功能。Button也有relief,按钮默认的relief是raised。与Label最不同的是,它还可以绑定一个点击事件。

参数名称作用
command点击按钮时运行(是一个方法)
repeatdelay延迟多少毫秒(1000ms=1s)后进行按钮的持续触发
repeatinterval按钮持续触发的间隔时长(毫秒)
overrelief鼠标经过时按钮的relief样式

常用方法:

方法作用
invoke调用Button的command(disabled无效)
flash使Button闪烁几次(在normal和active几次切换)

创建Button

下面我们就来创建一个Button,它可以绑定一个回调函数,点击时在屏幕上打印"你点了一下按钮"。

from tkinter import *root = Tk()def callback():    print("你点了一下按钮")button = Button(root, text="按钮", command=callback)button.pack()mainloop()

运行后点击按钮,可以看到如下输出。按钮可以多次点击。 

 

activeforeground和activebackground参数

如果鼠标长按按钮,那么按钮不会被触发,而是松开鼠标后触发。这时候,按钮处于一种激活状态。我们可以设置激活时按钮的前景和背景颜色:

Button(root, text="按钮", activeforeground="blue", activebackground="yellow")

如上面这段代码,把激活时的前景色设为blue(蓝色),背景色则设为yellow(黄色)。 点击时呈现这样的效果:

repeatdelay和repeatinterval参数

这两个参数可以用于按钮的持续触发。用户长按在按钮上,经过repeatdelay毫秒的延迟后,按钮将会重复触发,每次触发的间隔是repeatinterval毫秒。

from tkinter import *root = Tk()root.geometry("200x200")def addnum():    num = int(b.cget("text")) #获取组件的参数选项    b.config(text=str(num + 1))    b = Button(root, text="0", command=addnum,           repeatdelay=1000, repeatinterval=500)b.pack()mainloop()

效果:当用户按在按钮上面不动时,经过repeatdelay毫秒(1秒)后,按钮的command每间隔repeatinterval毫秒(0.5秒)就执行一次。

禁用按钮

所有组件都有state参数,表示组件的状态。一共有三个状态:normal, disabled, active。默认的state是normal,此时用户可以点击按钮。而处于disabled禁用的按钮,用户将无法点击。active则是激活状态。

Button(root, text="按钮", state="disabled")

处于禁用状态的按钮,无法点击:

 

处于激活状态的按钮如果不进行设置是看不出来的,但是设置了activebackground和activeforeground,就可以看出按钮处于激活状态。但是点击松开之后,激活状态就会取消(变成normal状态)。

根据这个原理,我们可以做出点击一次就禁用的按钮:

from tkinter import *root = Tk()def disable():    button.config(state="disabled")    button = Button(root, text="点击禁用", command=disable)button.pack()mainloop()

如果你忘了config的用法,这里再强调一次 :用于改变组件原本设定的参数,这个方法非常常用。

运行后点击一次按钮,按钮的状态由normal改为disabled,无法点击第二次。

点击后>>>

 2.3 布局管理(pack,grid,place)

上面已经提过,组件需要在创建后,摆放到屏幕上。一共有三种摆放的方式:pack, grid, place。注意:在同一个容器中,只能使用一种布局方式,要么组件都用pack,要么都用grid,要么都用place。接下来介绍一下这三个方法的参数:

pack

pack适用于简单的布局。

 

from tkinter import *root = Tk()root.geometry("200x200")w1 = Button(root, text="多余空间靠左")w1.pack(anchor="w")root.mainloop()

from tkinter import *root = Tk()root.geometry("200x80")w1 = Button(root, text="W1")w1.pack(expand=True)w2 = Button(root, text="W2")w2.pack(expand=True)root.mainloop()

 拖拽窗口后>>>

 如果不设置expand,则变成这样,组件不会自动适应窗口大小:

 拖拽窗口后>>>

参数设置未拖拽时效果拖拽后效果
fill="x"
fill="y"

fill="both"

fill="none"
from tkinter import *root = Tk()w1 = Button(root, text="Hello")w1.pack(padx=50, pady=30) #左右间隔50,上下间隔30root.mainloop()

 

from tkinter import *root = Tk()w1 = Button(root, text="Hello")w1.pack(padx=(50, 40), pady=(30, 60)) #左间隔50,右间隔40,上间隔30,下间隔60root.mainloop()

 

from tkinter import *root = Tk()root.geometry("400x200")w1 = Button(root, text="Hello")w1.pack(ipadx=40, ipady=40)root.mainloop()

  

grid

pack布局方式适合于简单的布局,在同一容器内,只能进行上下左右四方向的布局。而grid可以实现网格布局,根据行和列指定组件的位置。grid布局和pack一样都支持padx, pady, ipadx, ipady这几个参数。

from tkinter import *root = Tk()root.geometry("400x200")Button(root, text="0行0列").grid(row=0, column=0)Button(root, text="1行0列").grid(row=1, column=0)Button(root, text="0行1列").grid(row=0, column=1)Button(root, text="1行1列").grid(row=1, column=1)root.mainloop()

 可以看见,实现了整齐的布局。如果此时把column设置为一个很大的数字,比如999,但是容器上的组件只有1列,那么并不会把组件排放到999列,而是排放在2列的位置。

from tkinter import *root = Tk()root.geometry("400x200")Button(root, text="0行0列").grid(row=0, column=0)Button(root, text="1行0列").grid(row=1, column=0)Button(root, text="0行1列(占两行)").grid(row=0, column=1, rowspan=2)root.mainloop()

from tkinter import *root = Tk()root.geometry("400x200")Button(root, text="0行0列").grid(row=0, column=0)Button(root, text="0行1列").grid(row=0, column=1)Button(root, text="1行0列(占两列)").grid(row=1, column=0, columnspan=2)root.mainloop()

  

 如果在第二段代码的基础上,不加columnspan的设置,结果就会变成这样:

 

from tkinter import *root = Tk()root.geometry("400x200")Button(root, text="Helloooo").grid(row=0, column=0)Button(root, text="Hiiiiii").grid(row=0, column=1)Button(root, text="Hello").grid(row=1, column=0, sticky="e")root.mainloop()

也可以设置组件填充排放。x轴填充表示为"ew",y轴填充表示"ns",xy轴both填充设置为"nwse"

也可以设置填充时,同时靠某个方向排放。需要提供三个参数。比如x方向填充时同时靠北(n)排放,可以设置为sticky="ewn"。

place

place布局适用于更加复杂的,需要准确摆放组件的容器。这种布局不是很常用,因为使用比较麻烦,需要提供xy坐标以及组件的width和height(以像素为单位),place布局不支持padx……几个参数。

更改组件映射

规范地说,将组件排放布局到容器上,这个过程叫做映射(map)。widget.pack/grid/place()是映射一个组件,自然也有取消映射(Unmap)的方法。

这个方法是布局方法后面加上_forget,pack布局取消映射方法是pack_forget,grid则是grid_forget,place是place_forget。

调用后,相当于隐藏了这个组件。如果还想映射的话,再次调用一下pack/grid/place即可。

将组件布局,也有办法更改布局给的参数。pack_configure, grid_configure, place_configure,可以更改布局时给定的参数。

布局管理

综合使用布局管理,可以美化界面。布局的时候,组件和组件最好都空开一定距离,这样更加美观(pack和grid可以设置padx和pady)。不要把组件挤在一处,不要让窗口长宽比过大。同样,也不要让窗口大小超出屏幕大小,影响用户操作。

同一容器中只能使用一种布局方式,这就带来了一定麻烦和局限性。所以接下来将介绍Frame组件,使用它可以使布局管理更加方便。

2.4 Frame

Frame是框架的意思,让你在容器中能够创建一个子容器。使用Frame,可以对组件编组,也可以使你能够在一个窗口中综合使用不同的布局方式。比如,在窗口中使用pack布局,在窗口上的Frame中使用grid布局,这是允许的。

参考资料:Python Tkinter 框架控件(Frame) | 菜鸟教程

Frame(master=None, cnf={}, **kw)

Frame没有别的参数,只有几个基本参数,如relief, cursor, highlightcolor等。使用也很简单。

创建Frame

from tkinter import *root = Tk()root.geometry("200x200")fr = Frame(root)fr.pack()Button(fr, text="button in frame").pack()Button(fr, text="button2 in frame").pack()mainloop()

看上去,和没有Frame也没有什么区别,我们可以给Frame加上边框(设置relief参数)。注意,设置Frame的时候必须要更改它的边框宽度,即bd(borderwidth)。

fr = Frame(root, relief="solid", bd=2)

 

Frame的作用

Frame中可以添加容器中能添加的任何组件,甚至可以嵌套Frame。那么,使用Frame的意义是什么呢?可以参考下面几个作用:

from tkinter import *root = Tk()root.geometry("200x200")fr = Frame(root)fr.pack(padx=5, pady=5)Button(fr, text="1").pack(side="left")Button(fr, text="2").pack(side="left")Button(fr, text="3").pack(side="left")Button(root, text="OK").pack(pady=5)mainloop()

from tkinter import *root = Tk()root.geometry("200x200")fr = Frame(root)fr.pack(padx=5, pady=5)Button(fr, text="1").pack(side="left")Button(fr, text="2").pack(side="left")Button(fr, text="3").pack(side="left")Button(root, text="隐藏", command=fr.pack_forget).pack(pady=5)mainloop()

 点击隐藏按钮>>>

再比如,想要删除一部分组件,然后换成另外一部分组件,也可以使用Frame。只需要把这些组件放进一个Frame,然后遍历Frame的子组件,对组件挨个销毁即可。 

容器的winfo_children方法返回一个列表,包含了容器所有的子组件。destroy方法销毁一个组件,组件方法介绍时提到过。

for widget in frame.winfo_children():    widget.destroy() #逐个销毁frame的子组件

这样可以销毁Frame中的所有组件。

2.5 LabelFrame

这个组件与Frame类似,但是可以在左上方显示一段文本或是一个组件。

 

 

LabelFrame(master=None, cnf={}, **kw)

参数名称作用
text显示的文本
font文本的字体
labelanchor文本位于Frame的方位
labelwidget用一个组件替代显示的文本

创建LabelFrame

from tkinter import *root = Tk()root.geometry("200x200")fr = LabelFrame(root, text="LabelFrame")fr.pack(fill="both", padx=4)Button(fr, text="1").pack()Button(fr, text="2").pack()mainloop()

labelanchor参数

labelanchor参数设置文本的位置,可选有八个方位,但不包括center,默认是nw。下面是两个示例。

labelwidget参数

如果你不想要LabelFrame的上面显示一段文字,也可以把它替换为别的组件,比如Button。这个组件的master不影响,只要在同一父容器中就行。

from tkinter import *root = Tk()root.geometry("200x200")fr = LabelFrame(root, text="LabelFrame", labelwidget=Button(root, text="按钮"))fr.pack(fill="both", padx=4)Button(fr, text="1").pack()Button(fr, text="2").pack()mainloop()

 

2.6 Entry

Entry是一个文本框组件,用户可以在里面输入文本。

参考资料:Python ---(六)Tkinter窗口组件:Entry_近视的脚踏实地的博客-CSDN博客

 

Entry(master=None, cnf={}, **kw)

参数名称作用
font输入文本字体
show输入文本被显示为什么字符
selectbackground选中文字的背景色
selectforeground选中文字颜色
insertborderwidth光标边框宽度(指定时光标样式为raised)
insertontime光标闪烁时,处于“亮”状态的时长(毫秒)
insertofftime光标闪烁时,处于“灭”状态的时长(毫秒)
insertwidth光标的宽度
selectborderwidth选中文字的背景边框宽度
textvariable绑定的StringVar,同步Entry输入的内容
readonlybackground文本框处于readonly状态下的背景颜色
xscrollcommandx方向滚动条(后面介绍)
validate验证输入合法性的条件

vcmd

validatecommand

判断输入合法性的回调函数,或者是一个包含回调和所需参数的元组

invcmd

invalidcommand

输入不合法时执行的回调函数

常用方法:

方法名称作用
get()获取文本框的值
delete(first, last=None)删除文本框中从索引first到last的内容
insert(index, s)在文本框中插入文本,index是索引,s是插入内容
select_range(start, end)选中从start到end的文本
icursor(index)将光标移动到索引处

创建Entry

from tkinter import *root = Tk()root.geometry("200x200")ent = Entry(root)ent.pack()mainloop()

 

 出现了一个输入框,可以在里面自由输入内容。

show参数

指定show参数,可以使输入里面的内容显示为一个字符,常用于密码输入。下面的示例,将所有的输入内容显示为*号。

from tkinter import *root = Tk()root.geometry("200x200")Label(root, text="Pwd: ").pack()ent = Entry(root, show="*")ent.pack()mainloop()

无论输入什么内容,都是*号显示。

get方法

get方法获取文本框的值,如下示例:

from tkinter import *root = Tk()root.geometry("200x200")ent = Entry(root)ent.pack()def printget():    print(ent.get())    Button(root, text="获取输入", command=printget).pack()mainloop()

点击按钮,将会输出文本框中的值。

insert和delete方法

insert方法可以插入一段内容,需要指定一个插入的位置和插入的内容。

插入位置可以是是字符的索引,比如0代表在第一个字符前面插入。也可以是一些特殊的值,比如"end"(在结尾处插入), "insert"(在光标闪烁处插入) 

delete方法则用于删除一段内容,需要指定删除的开始和结束位置。位置的设定和insert一样。

tkinter还有一些类也有这两个方法,索引的用法也都基本一样。

readonly状态

Entry可以设置为state="readonly",也就是只读状态。处于readonly的Entry不能被输入,但是用户可以选中Entry里面插入的内容,当然也可以复制。如果是disabled状态,用户不但不能输入,而且不能选中里面的内容。

输入验证

validate, validatecommand, invalidcommand这三个参数用于输入验证。输入验证,也就是判断用户在Entry里面输入的内容是否符合要求。

validate参数是输入的条件,也就是在什么情况下,开启输入验证的功能。可以有"focus", "focusin", "focusout", "key", "all", "none"这几个可选。

参数值解释
focus当组件获得或失去焦点时验证
focusin当组件获得输入焦点(光标闪烁)时验证
focusout当组件失去输入焦点时验证
key当输入内容更改时验证,如果验证为False,输入内容不会被插入文本框
all当上述任何一种情况出现时验证
none不进行验证(默认值)

validatecommand是验证的函数,invalidcommand是验证失败时执行的方法。验证条件成立时,会调用validatecommand方法,这个方法要有一个True或False的返回值。如果是True,则验证通过;如果是False,则验证不通过,将会执行invalidcommand方法。

下面是一个示例,只有输入数字才会通过验证。

from tkinter import *root = Tk()root.geometry("200x200")def vld():    if e.get().isdigit():        print("数字,符合要求")        return True    else:        print("不是数字,不符合要求")        return Falsedef wrong():    print("输入不符合要求,调用invalidcommand")    e = Entry(root, validate="focusout", validatecommand=vld, invalidcommand=wrong)e.pack()mainloop()

运行效果:当输入一个数字,然后把焦点转移(激活另外一个可输入窗口)时,打印“数字,符合要求”。当输入的不是数字时,打印“不是数字,不符合要求”和"输入不符合要求,调用invalidcommand"两句。

validatecommand参数还可以给一个元组(callback, v1, v2, v3, ...),包含执行的方法和你希望Entry传递给方法的参数。

参数选项解释
%d传递一个操作代码:0表示删除操作,1表示插入操作,-1表示textvariable内容被程序更改或组件失去/获得焦点
%i传递用户插入或删除内容的索引位置,如果是失去/获得焦点或textvariable内容被程序更改,传递-1
%P传递文本框最新的输入内容
%s传递调用验证函数前,文本框上一次的输入内容
%S传递文本框输入或删除的内容
%v传递当前validate参数的值
%V传递调用验证函数的原因,是"focusin"(获得焦点), "focusout"(失去焦点), "key"(输入或删除文本框内容), "forced"(textvariable被程序修改)
%W组件名称(Tcl内部名称)

比如,把validatecommand设为(callback, "%P", "%s"),那么在调用callback的时候会传递两个参数,一个是文本框最新的输入内容,一个是文本框上一次的输入内容。

需要说明的是,使用validatecommand传递元组的时候,不能直接传递普通的函数,需要注册为Tcl函数才能使用输入验证。注册方法是:

tcl_cmd = root.register(cmd)

下面的一个示例,演示了validatecommand传参。 

from tkinter import *root = Tk()root.geometry("200x200")def vld(s):    print("输入或删除了", s)    return Truevld = root.register(vld) #注册为Tcl函数e = Entry(root, validate="key", validatecommand=(vld, "%S"))e.pack()mainloop()

实例:密码验证系统

下面的一个实例中,用户需输入一串正确的密码,否则无法通过验证。

from tkinter import *correct_pwd = "0123456789" #正确的密码root = Tk()root.title("密码验证系统")def ok():    if pwd.get() == correct_pwd:        print("验证通过!")        root.destroy()    else:        print("验证失败!")        pwd = Entry(root, show="*")pwd.pack()Button(root, text="OK", command=ok).pack()root.mainloop()

 

2.7 事件绑定

组件的bind方法可以使组件绑定一个事件和一个回调函数,事件有按下某个键,点击组件等,一般是由用户引发的。事件会被传递给回调函数,然后执行函数。

Widget.bind(sequence=None, func=None)

sequence是事件序列,func是检测到事件的回调函数。

参考资料:Tkinter 事件绑定

按键名称

此处只选取一些常用的按键,更多按键名请参考:keysyms manual page - Tk Built-In Commands

按键名(keysym)   按键码(keycode)       代表的按键Alt_L                64                左边的Alt按键Alt_R                113               右边的Alt按键BackSpace            22                BackSpace(退格)按键Cancel               110               break按键Caps_Lock            66                CapsLock(大写字母锁定)按键Control_L            37                左边的ControlControl_R            109               右边的ControlDelete               107               Delete按键Down                 104               ↓按键End                  103               End按键Escape               9                 Esc按键Execute              111               SysReq按键F1                   67                F1按键F2                   68                F2按键F3                   69                F3按键F4                   70                F4按键F5                   71                F5按键F6                   72                F6按键F7                   73                F7按键F8                   74                F8按键F9                   75                F9按键F10                  76                F10按键F11                  77                F11按键F12                  96                F12按键Home                 97                Home按键Insert               106               Insert按键Left                 100               ←按键Linefeed             54                Linefeed(Ctrl + J)KP_0                 72                小键盘数字0KP_1                 73                小键盘数字1KP_2                 74                小键盘数字2KP_3                 75                小键盘数字3KP_4                 76                小键盘数字4KP_5                 77                小键盘数字5KP_6                 78                小键盘数字6KP_7                 79                小键盘数字7KP_8                 80                小键盘数字8KP_9                 81                小键盘数字9KP_Add               86                小键盘的+按键KP_Begin             84                小键盘的中间按键(5)KP_Decimal           91                小键盘的点按键(.)KP_Delete            91                小键盘的删除键KP_Divide            112               小键盘的/按键KP_Down              88                小键盘的↓按键KP_End               87                小键盘的End按键KP_Enter             108               小键盘的Enter按键KP_Home              79                小键盘的Home按键KP_Insert            90                小键盘的Insert按键KP_Left              83                小键盘的←按键KP_Mutiply           63                小键盘的*按键KP_Next              89                小键盘的PageDown按键KP_Prior             81                小键盘的PageUp按键KP_Right             85                小键盘的→按键KP_Subtract          82                小键盘的-按键KP_Up                80                小键盘的↑按键Next                 105               PageDown按键Num_Lock             77                NumLock(数字锁定)按键Pause                110               Pause(暂停)按键Print                111               PrintScrn(打印屏幕)按键Prior                99                PageUp按键Return               36                Enter(回车)按键Right                102               →按键Scroll_Lock          78                ScrollLock按键Shift_L              50                左边的Shift按键Shift_R              62                右边的Shift按键 Tab                  23                Tab(制表)按键Up                   98                ↑按键

sequence

事件序列遵从一定的格式,如果不合理将会报错:

外面由<>尖括号括起来,中间由-减号隔开。 modifier是条件,表示只有当modifier成立的时候才会执行函数,可以有多个;type是主要事件的类型,当type有detail的时候可以省略type(有时候可能弄混);Detail是事件类型的附带描述,有的事件类型需要Detail,但有的不需要。

这可能有些难懂,下面将详细解析。

type是事件的类型,下面是type的名称:

type触发条件detail

Button

ButtonPress

用户点击鼠标1:鼠标左键;2:鼠标中键;3:鼠标右键;4:滑轮向上滚动(Linux);5:滑轮向下滚动(Linux)
ButtonRelease鼠标按键释放1:鼠标左键;2:鼠标中键;3:鼠标右键;4:滑轮向上滚动(Linux);5:滑轮向下滚动(Linux)
Active组件被激活
Deactivate组件失去激活
Enter光标进入组件范围(不是按下回车键)
Leave光标离开组件范围

Key

KeyPress

用户按下按键可以指定具体的按键名,参见前面的按键表
KeyRelease用户释放按键可以指定具体的按键名,参见前面的按键表
Map组件被映射
Unmap组件取消映射
FocusIn组件获得焦点
FocusOut组件失去焦点
Configure组件尺寸被调节或拖拽
Destroy组件被销毁
Expose窗口或组件的某部分不再被覆盖
Motion光标在组件内移动
MouseWheel鼠标滚动(Windows和Mac;Linux应为Button-4、5)
Visibility窗口在屏幕中可见(比如还原最小化、窗口由隐藏变为显示时触发)

下面是一个示例,演示了bind方法。

from tkinter import *def callback(event):    Label(root, text="你点了一下").pack()root = Tk()root.geometry("400x200")root.title("点击窗口")root.bind("", callback)mainloop()

 点击几次窗口>>>

事件序列中,Button是type,意思是点击鼠标,后面的1是detail,表示鼠标左键。同样,如果想要用鼠标中键可以改为Button-2,右键可以改为Button-3。如果不指定detail,只是Button,那么三个鼠标键点击都会被检测到。

callback是回调函数,它必须带有一个参数让bind方法传递。当检测到Button-1事件的时候,bind方法会将一个Event对象传递给callback函数的第一个参数,让函数中能够处理检测到事件的信息。下面就来介绍Event对象。

Event

tkinter.Event返回一个Event对象。Event对象在bind绑定时会传递给回调函数。大多数Event是所有事件类型可共用的,但有一些不是。下面是Event的属性。

属性解释仅限事件类型
widget发生事件的组件
serial事件序列号
type事件类型
time发生事件的时间
x鼠标在窗口中的x位置
y鼠标在窗口中的y位置
x_root鼠标在整个屏幕上的x位置Button, ButtonRelease, Key, KeyRelease, Motion
y_root鼠标在整个屏幕上的y位置Button, ButtonRelease, Key, KeyRelease, Motion
num鼠标按下的键Button, ButtonRelease
focus窗口是否有焦点Enter, Leave
width窗口的宽度Configure, Expose
height窗口的高度Configure, Expose
keycode按键代码(上面的按键表中有)Key, KeyRelease
char按键的字符Key, KeyRelease
keysym按键名称Key, KeyRelease
keysym_num按键名称的数字形式Key, KeyRelease
state事件状态(数字)Button, ButtonRelease, Key, KeyRelease, Enter, Leave, Motion
state事件状态(字符串)Visibility
delta滚轮滚动信息MouseWheel

下面是一个用法示例。 

from tkinter import *def callback(event):    print("事件类型", event.type)    print("点击了鼠标键", event.num)    print("事件发生在组件", event.widget)root = Tk()root.geometry("400x200")root.title("点击窗口")root.bind("

 运行后点击几次窗口:

Modefier可以指定一些条件,条件成立的时候,才会捕获事件。

Modefier可以是以下内容:

modefier成立条件
Alt用户按着Alt键
Control用户按着Ctrl键
Shift用户按着Shift键

Button1

B1

用户按着鼠标左键

Button2

B2

用户按着鼠标中键

Button3

B3

用户按着鼠标右键

Button4

B4

用户将鼠标滚轮向上滚动(Linux)

Button5

B5

用户将鼠标滚轮向下滚动(Linux)
Double后面的事件类型被连续两次触发,常用于:双击鼠标左键()
Triple后面的事件类型被连续三次触发

比如,想要达到检测组合键的效果,按下Ctrl+S的时候,执行某些操作,即可表示为(bind区分大小写,会区分大写字母和小写字母),这里的Control是一个modefier,是可选的,不写也是一个合理的事件。

这个Control要和Key事件类型的Control_L和Control_R区分开来。如果要单独检测一个Ctrl键,就必须要用Control_L和Control_R,而不能使用条件,因为事件类型才是必选的。

再比如,检测双击鼠标和三击鼠标,事件分别是

bind_all方法

bind_all方法可以在一个窗口中,绑定所有的子组件。比如想要把一个窗口里面的所有组件都绑定,那么就可以用root.bind_all("", callback)。这样就不需要很麻烦地一个一个组件地绑定。

如果只是bind_all窗口里面的一个组件,那么整个窗口的组件也会被绑定。

虚拟事件

tkinter中同样可以定义自己的事件,也就是虚拟事件,事件格式略有不同,表示为<>,event是事件名,用两层尖括号括起来。当窗口检测到虚拟事件的时候,会执行绑定的回调函数并传递一个event。

既然是自定义事件,那么触发方式也需要自定。event_generate方法可以向组件发送一个事件。这个事件可以是自定义事件,也可以不是自定义事件,而是

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯