声明:该文章是个人学习中写的,目的是总结及当作工具参考,有一定的借鉴成分,后续若有新发现则补充
目录
Tkinter简介
Tkinter是python默认的GUI库,像python IDLE就是用Tkinter设计出来的。导入时可以直接导入:
import tkinter
简单示例:
from tkinter import *
root = Tk() #实例化Tk类
Label1 = Label(root,text = 'hello') #在root中创建内容为“hello”的Label
Label1.pack() #自动调节Label1尺寸
root.mainloop() #进入消息循环
进阶示例:
import tkinter as tk
class App:
def __init__(self, root): #接收Tk的实例化对象root
frame = tk.Frame(root) #在root中创建一个Frame框架
frame.pack() #自动调节frame尺寸
#创建文字为“hello”的按钮,按下执行say_hello
self.hi_there = tk.Button(frame, text="hello", fg="green", command=self.say_hello)
self.hi_there.pack(side=tk.LEFT)
def say_hi(self):
print("Hello everyone!")
root = tk.Tk()
app = App(root)
root.mainloop()
通过上述例子可以看到发现,基本上所有tkinter设计的窗口,都要经过以下几个步骤:
- 实例化 Tk() 为root(名称自取)
- 在root中创建其他组件
- 调用 pack() 方法自动调节组件尺寸
- 执行 mainloop() 进入消息循环
创建组件基本语法
基本上所有的组件创建,都遵循以下语法:
创建窗体——在窗体上创建组件
窗体变量 = Tk()
组件变量 = 组件名称(窗体变量 ,组件参数)
若要指定组件格式,需在创建组件变量时,通过参数进行修改。创建组件变量后无法修改
Tkinter组件汇总
名称 | 含义 |
---|---|
Button | 按钮 |
Canvas | 绘图形组件,可以在其中绘制图形 |
Checkbutton | 复选框 |
Entry | 文本框(单行) |
Text | 文本框(多行) |
Frame | 框架,将几个组件组成一组 |
Label | 标签,可以显示文字或图片 |
Listbox | 列表框 |
Menu | 菜单 |
Menubutton | 它的功能完全可以使用Menu替代 |
Message | 与Label组件类似,但是可以根据自身大小将文本换行 |
for | 单选框 |
Scale | 滑块;允许通过滑块来设置一数字值 |
Scrollbar | 滚动条;配合使用canvas, entry, listbox, and text窗口部件的标准滚动条; |
Toplevel | 用来创建子窗口窗口组件 |
Variable 类
有些控件如Entry输入框、Checkbutton复选框、Radiobutton单选框等。有时希望将他们的值与一个变量绑定起来:若变量自身变化,将变化同步到组件值中;若组件中的值变化,将变化同步到变量中。
如刚说的三种组件,给其中的参数 variable 或 textvariable 赋值,就需要用到Tkinter自带的 Variable 类方可实现变量绑定。
Variable类下主要有4种子类,分别对应文本型、整型、浮点型、布尔型变量:
参数 | 含义 |
---|---|
StringVar() | 保存一个 string 类型变量, 默认值为"" |
IntVar() | 保存一个整型变量, 默认值为0 |
DoubleVar() | 保存一个浮点型变量, 默认值为0.0 |
BooleanVar() | 保存一个布尔型变量, 返回值为 0 (代表 False) 或 1 (代表 True) |
对变量的值进行读写主要通过两种方法:get()、set()
在使用时,可以先将变量实例化,然后赋值给组件类,实现变量绑定。在给组件赋值后,通过get()获取变量值。
如:
from tkinter import *
root= Tk()
v1 = StringVar() #创建String型变量
Entry = Entry(root,textvariable=v1) #将变量与Entry组件绑定
Entry.pack(padx=5,pady=5)
root.mainloop()
print(v1.get()) #将输出的内容打印
运行结果如下:
在输入框中输出内容后关闭窗口,即可打印刚才输出的内容
修改一下代码,看看set()是如何运行的:
from tkinter import *
root= Tk()
v1 = StringVar() #创建string型变量
v1.set('hello') #给变量赋初始值
Entry = Entry(root,textvariable=v1) #将变量与Entry组件绑定
Entry.pack(padx=5,pady=5)
root.mainloop()
运行结果如下:
接着,我们尝试给v1赋值为数值123,看看会不会出现什么不一样的地方:
from tkinter import *
root= Tk()
v1 = StringVar()
v1.set(123)
Entry = Entry(root,textvariable=v1)
Entry.pack(padx=5,pady=5)
root.mainloop()
print(v1.get()+1)
运行结果如下:
窗体显示并没有什么问题,能够显示123。但是关闭窗体后,将123与1相加,出现了 TypeError 异常:
我们将1修改为字符串,得到结果1231:
所以,我们可以得出一个结论:对于文本型变量,即使赋值为数值,仍然会转化为文本型
那么我们对整型变量赋值为数值会出现什么情况?修改代码如下:
from tkinter import *
root= Tk()
v1 = IntVar()
v1.set('123')
Entry = Entry(root,textvariable=v1)
Entry.pack(padx=5,pady=5)
root.mainloop()
print(v1.get()+1) #输出结果:124
可以发现,如果我们输入的是文本型数值,仍然能自动转化为整型。但是当我们输入的不是数值型文本时,会出现什么情况?
from tkinter import *
root= Tk()
v1 = IntVar()
v1.set('hello')
Entry = Entry(root,textvariable=v1)
Entry.pack(padx=5,pady=5)
root.mainloop()
print(v1.get())
运行截图如下:
即使是赋值为纯文本值,也不会出现异常。那么关闭窗体,执行调用v1的代码,结果如下
_tkinter.TclError: expected floating-point number but got "hello"
很显然,此时获取v1的值时,出现了_tkinter.TclError异常,告诉我们赋值为文本是错误的。
由此,我们可以得出如下结论
- 给变量赋值时,会对值自动执行如 int() , str()等函数,将值转化为变量指定类型
- 即使赋值为错误的类型,也不会抛出异常
- 只有在获取变量错误值时,会抛出_tkinter.TclError异常
常见参数详解
anchor——表示文本的位置
除了LabelFrame组件有12个参数: ‘e’、‘s’、‘w’、‘n’、‘es’、‘ws’、‘en’、‘wn’、‘ne’、‘nw’、‘se’、‘sw’ 等十二个方位
其他的组件anchor都只有:W,S,E,N,WS,WN,ES,EN,CENTER(默认)九个方位
background(简称bg)——背景色
foreground(简称fg)——前景色
font——字体
设置字体,可以是
布局管理器
pack
pack的布局原则是:按添加顺序排列组件。相比于grid,pack更适合少量组件的排列。通常来说,尽量不要在同一个父组件中混合使用grid和pack。
基本语法为:
组件.pack(anchor, expand, fill, ipadx, ipady, padx, pady, side)
- anchor:当可用空间大于组件所需求的大小时,该选项决定组件被放置在容器的何处。可设置为: N、E、S、W、NW、NE、SW、SE、CENTER(默认值),表示9个方位
- expand:指定当父容器增大时才是否拉伸组件,设置为Bool值
- fill:设置组件是否沿水平或垂直方向填充。可设置为: NONE、X、Y、BOTH ,其中 NONE 表示不填充,BOTH 表示沿着两个方向填充
- ipadx:指定组件在 x 方向(水平)上的内部留白
- ipady:指定组件在 y 方向(垂直)上的内部留白
- padx:指定组件在 x 方向(水平)上与其他组件的间距
- pady:指定组件在 y 方向(垂直)上与其他组件的间距
- side:设置组件的添加位置,可以设置为 TOP、BOTTOM、LEFT、RIGHT
示例:将一个组件放到另一个组件中,并填满
from tkinter import *
root = Tk()
listbox = Listbox(root)
listbox.pack(fill=BOTH, expand=True)
for i in range(10):
listbox.insert(END, str(i))
mainloop()
结果如下:
fill 会告诉管理器,该组件将填充整个分配给他的空间,BOTH表示同时纵向横向,X表示横向,Y表示纵向;expand选项是告诉窗口管理器将父组件的额外空间也填满。
默认情况下,pack是将添加的组件依次纵向排列,可通过更改side改变排列方向
grid
grid管理器,相当于一个表格,将组件放入表格中,形成一个规范的表格布局。在使用grid排列组件时,只需要传递(row 行,column 列)参数即可。此外,使用grid并不需要指明表格的尺寸,管理器会自动计算。
示例:创建一个带头像的登陆器
from tkinter import *
root = Tk()
Label(root, text="用户名").grid(row=0, sticky=W)
Label(root, text="密码").grid(row=1, sticky=W)
Entry(root).grid(row=0, column=1)
Entry(root, show="*").grid(row=1, column=1)
photo = PhotoImage(file="image/18.gif")
Label(root, image=photo).grid(row=0, column=2, rowspan=2, padx=5, pady=5)
Button(text="提交", width=10).grid(row=2, columnspan=3, pady=5)
mainloop()
运行如下:
默认情况下,grid 会将组件居中显示在网格中,若需要修改方向,可以设置sticky参数来更改。sticky参数值 与组件的 anchor 参数一样,为WSEN及其组合的方位。
如果要实现合并单元格(多网格放一个组件)的操作,设置rowspan和columnspan即可(见上例)
place
place 是通过指定相对于父组件的相对位置,来实现布局的。由于不同的组件可能尺寸不一等,要让组件对齐相当麻烦,因此在布局上不如前两个管理器。但是 place 可以实现覆盖布局。如果用坐标系来解释的话:pack 是在x 或y 轴上排列,grid 则是在xy坐标系中排列,而place则是在xyz坐标系中排列。
示例:创建一个RGB三色的矩形重叠形状
from tkinter import *
root = Tk()
Label(root, bg="red").place(relx=0.5, rely=0.5, relheight=0.75, relwidth=0.75, anchor=CENTER)
Label(root, bg="green").place(relx=0.5, rely=0.5, relheight=0.5, relwidth=0.5, anchor=CENTER)
Label(root, bg="blue").place(relx=0.5, rely=0.5, relheight=0.25, relwidth=0.25, anchor=CENTER)
mainloop()
运行如下:
在示例中,可以看到5个参数 relx、rely、relwidth、relheight、anchor,分别表示 相对于父组件的x位置、y位置、宽度、高度及方位。前四个参数都是以父对象为基准参考的,值都在0.0~1.0中,表示相对于父组件的位置及尺寸。如要显示在父组件中间,则令relx、rely为0.5,要有父组件四分之一大,则relheight及width为0.5
组件详解
Label 标签
用于在界面上输出描述的标签,可以是文字,也可以是图片
参数 | 含义 |
---|---|
Anchor | 标签中文本的位置 |
background(bg) | 背景色 |
foreground(fg) | 前景色 |
borderwidth(bd) | 边框宽度 |
width | 标签宽度 |
height | 标签高度 |
bitmap | 标签中的位图 |
font | 字体 |
compound | 文本和图像的混合模式 |
image | 标签中的图片 |
justify | 多行文本的对齐方式 |
text | 标签中的文本,可以使用’\n’表示换行 |
textvariable | 显示文本自动更新,与StringVar等配合着用 |
from tkinter import *
root= Tk()
label = Label(root,text="hello")
label.pack()
root.mainloop()
运行如下:
Botton 组件
用于创建一个按钮,除了设置按钮格式外,可以给按钮指定一个单击时触发的函数或方法
参数 | 含义 |
---|---|
anchor: | 指定按钮上文本的位置 |
background(bg) | 指定按钮的背景色 |
bitmap | 指定按钮上显示的位图 |
borderwidth(bd) | 指定按钮边框的宽度 |
command: | 指定按钮消息的回调函数 |
cursor: | 指定鼠标移动到按钮上的指针样式 |
font: | 指定按钮上文本的字体 |
foreground(fg) | 指定按钮的前景色 |
height: | 指定按钮的高度 |
image: | 指定按钮上显示的图片 |
state: | 指定按钮的状态(disabled) |
text: | 指定按钮上显示的文本 |
width: | 指定按钮的宽度 |
padx | 设置文本与按钮边框x的距离,还有pady |
activeforeground | 按下时前景色 |
textvariable | 可变文本,与StringVar等配合着用 |
Checkbutton 多选框/Radiobotton 单选框
Radiobotton为常见的单选框,根据是否选中,返回0、1
Checkbutton为常见的多选框,根据是否选中,返回0、1
参数 | 含义 |
---|---|
text | 显示文本内容 |
command | 指定Radiobutton的事件处理函数 |
image | 可以使用gif图像,图像的加载方法img = PhotoImage(root,file = filepath) |
bitmap | 指定位图,如bitmap= BitmapImage(file = filepath) |
value | 指定同一组的单选框的值 |
variable | 控制变量,跟踪Radiobutton的状态,On(1),Off(0) |
master | 代表了父窗口 |
bg | 背景色,如bg=”red”, bg="#FF56EF" |
fg | 前景色,如fg=”red”, fg="#FF56EF" |
font | 字体及大小,如font=(“Arial”, 8),font=(“Helvetica 16 bold italic”) |
height | 设置显示高度、如果未设置此项,其大小以适应内容标签 |
relief | 指定外观装饰边界附近的标签,默认是平的,可以设置的参数:flat、groove、raised、ridge、solid、sunken |
width | 设置显示宽度,如果未设置此项,其大小以适应内容标签 |
wraplength | 将此选项设置为所需的数量限制每行的字符,数默认为0 |
state | 设置组件状态;正常(normal),激活(active),禁用(disabled) |
selectcolor | 设置选中区的颜色 |
selectimage | 设置选中区的图像,选中时会出现 |
underline | With the default value of -1, none of the characters of the text label are underlined. Set this option to the inde |
bd | 设置Radiobutton的边框大小;bd(bordwidth)缺省为1或2个像素 |
textvariable | 设置Radiobutton的textvariable属性,文本内容变量 |
padx | 标签水平方向的边距, 默认为1像素 |
pady | 标签竖直方向的边距, 默认为1像素. |
justify | 标签文字的对齐方向, 可选值为 RIGHT, CENTER, LEFT, 默认为 CENTER |
LabelFrame 带有标签的框架
与常规的Frame框架不同,LabelFrame框架带有Label标签,该标签可以是文字也可以是GUI组件。是Frame的升级版,可以让组件分组更加简洁直观
参数 | 含义 |
---|---|
bg | The normal background color displayed behind the label and indicator. |
bd | The size of the border around the indicator. Default is 2 pixels. |
cursor | If you set this option to a cursor name (arrow, dot etc.), the mouse cursor will change to that pattern when it is over the checkbutton. |
font | The vertical dimension of the new frame. |
height | The vertical dimension of the new frame. |
labelAnchor | 设置标签的位置。该选项支持 ‘e’、‘s’、‘w’、‘n’、‘es’、‘ws’、‘en’、‘wn’、‘ne’、‘nw’、‘se’、‘sw’ 这 12 个边项值,用于控制标签的位置。 |
highlightbackground | Color of the focus highlight when the frame does not have focus. |
highlightcolor | Color shown in the focus highlight when the frame has the focus. |
highlightthickness | Thickness of the focus highlight. |
relief | With the default value, relief=FLAT, the checkbutton does not stand out from its background. You may set this option to any of the other styles |
text | Specifies a string to be displayed inside the widget. |
width | Specifies the desired width for the window. |
Entry 输入框
用于输入信息,如用户名密码等。
参数 | 含义 |
---|---|
background(bg) | 文本框背景色; |
foreground(fg) | 前景色; |
selectbackground | 选定文本背景色; |
selectforeground | 选定文本前景色; |
borderwidth(bd) | 文本框边框宽度; |
font | 字体; |
show | 文本框显示的字符,若为*,表示文本框为密码框; |
state | 状态; |
width | 文本框宽度 |
textvariable | 可变文本,与StringVar等配合着用 |
validate | 设置验证类型 |
validatecommand | 指定一个验证函数,函数返回值为Bool |
invalidatecommand | 当validatecommand返回False时调用 |
获取组件中的内容,可以设置variable类变量,也可以直接使用get()方法
插入内容使用 insert() 方法,删除内容使用 delete() 方法。
如删除所有内容:Entry.delete(0,END)
插入指定文本:Entry.insert(0,"指定文本")
示例:创建一个登录框
from tkinter import *
root = Tk()
root.title("示例")
Label(root,text="用户名").grid(row=0)
Label(root,text="密码").grid(row=1)
e1 = Entry(root)
e2 = Entry(root,show="*")
e1.grid(row=0,column=1,padx=10,pady=5)
e2.grid(row=1,column=1,padx=10,pady=5)
def extract():
print('用户名:',e1.get())
print('密码:',e2.get())
e1.delete(0,END)
e2.delete(0,END)
Button(root,text="登录",width=10,command=extract).grid(row=3,column=0,padx=10,pady=5,sticky=W) #sticky表示位置
Button(root,text="退出",width=10,command=root.quit).grid(row=3,column=1,padx=10,pady=5,sticky=E)
mainloop()
运行如下:
除了基本的输入信息之外,Entry组件还支持验证功能,用于判断输入内容是否“合法”
首先需要设置validate参数,作为开启验证功能的开关。可设置的值如下:
值 | 含义 |
---|---|
focus | 当 Entry 组件获得或失去焦点的时候验证 |
focusin | 当 Entry 组件获得焦点的时候验证 |
focusout | 当 Entry 组件失去焦点的时候验证 |
key | 当输入框被编辑的时候验证 |
all | 当上面任何一种情况出现时验证 |
none | 关闭验证功能(默认值),注:是字符串 none 而不是None |
其次设置 validatecommand 参数,指定一个返回值为True 或 False 的验证函数
最后,当 validatecommand 指定的函数返回 False 时,触发 invalidatecommand 参数指定的返回值为bool类型的函数
示例:创建一个验证框,用户名为 admin 时输出“名称合法”,否则“请重新输入”
from tkinter import *
def func1():
if e1.get() == "admin":
print('名称合法')
return True
else:
return False
def func2():
print("请重新输入")
e1.delete(0,END)
return True
root = Tk()
root.title("示例")
Label(root,text="用户名").grid(row=0)
Label(root,text="密码").grid(row=1)
#当用户框失去焦点时验证
e1 = Entry(root,validate="focusout",validatecommand=func1,invalidcommand=func2)
e2 = Entry(root,show="*")
e1.grid(row=0,column=1,padx=10,pady=5)
e2.grid(row=1,column=1,padx=10,pady=5)
mainloop()
若设置为key,需要单次输入符合条件的内容,否则无法输入
使用验证功能时,还可以设置一些额外参数:
参数 | 含义 |
---|---|
%d | 操作代码:0 表示删除操作;1 表示插入操作;2 表示获得、失去焦点或textvariabel值被修改 |
%i | 当用户尝试插入或删除操作时,该参数表示插入或删除的位置(索引号),如果是因为获得、失去焦点或 textvariable 值被修改而调用验证函数,那么值为 -1 |
%P | 当输入框的值允许改变的时候,该值有效。该值为输入框的最新文本内容 |
%s | 该值为调用验证函数前输入框的文本内容 |
%S | 当插入或删除操作触发验证函数的时候,该值有效。该参数表示文本被插入和删除的内容 |
%v | 该组件当前的 validte 参数的值 |
%V | 调用验证函数的原因,该值是“focusin”,“focusout”,“key”或“forced”(textvriable 参数值被修改)中的一个 |
%W | 该组件的名字 |
使用这些额外参数前,需要先使用register()方法将验证函数包装,再将包装后的验证函数和额外参数组合为元组传递
以上面的例子为例,修改一下:
from tkinter import *
def func1(act,index,content,old_content,validate,reason,name):
if e1.get() == "admin":
print('名称合法')
print(act,index,content,old_content,validate,reason,name)
return True
else:
print('请重新输入')
print(act,index,content,old_content,validate,reason,name)
return False
root = Tk()
root.title("示例")
Label(root,text="用户名").grid(row=0)
Label(root,text="密码").grid(row=1)
test = root.register(func1)
e1 = Entry(root,validate="focusout",validatecommand=(test,"%d","%i",'%P','%s','%v','%V','%W'))
e2 = Entry(root,show="*")
e1.grid(row=0,column=1,padx=10,pady=5)
e2.grid(row=1,column=1,padx=10,pady=5)
mainloop()
运行如下:
调用验证函数,输出结果为:
名称合法
-1 -1 admin admin focusout focusout .!entry
Listbox 列表框
当页面空间有限,而选项比较多时,使用列表框来存放诸多选项是比较好的选择
参数 | 含义 |
---|---|
master | 代表了父窗口 |
bg | 背景色,如bg=”red”, bg="#FF56EF" |
fg | 前景色,如fg=”red”, fg="#FF56EF" |
height | 设置显示高度、如果未设置此项,其大小以适应内容标签 |
relief | 指定外观装饰边界附近的标签,默认是平的,可以设置的参数:flat、groove、raised、ridge、solid、sunken |
width | 设置显示宽度,如果未设置此项,其大小以适应内容标签 |
state | 设置组件状态;正常(normal),激活(active),禁用(disabled) |
bd | 设置Button的边框大小;bd(bordwidth)缺省为1或2个像素 |
selectmode | 选择模式: SINGLE(单选) ROWSE(可通过鼠标或方向键改变的单选) MULTIPLE(多选) EXTENDED(可通过shift和ctrl配合使用,或鼠标拖动进行的多选) |
listvariable | 设置listvariable属性 |
创建Listbox时,内容为空,需要手动添加内容。若内容较多,应使用循环添加
示例:创建一个单击按钮删除选项的 Listbox:
from tkinter import *
root = Tk()
# 创建一个空列表
theLB = Listbox(root, setgrid=True)
theLB.pack()
# 往列表里添加数据
for item in ["钢铁侠", "蜘蛛侠", "绿灯侠", "神奇女侠"]:
theLB.insert(END, item)
theButton = Button(root, text="删除", command=lambda x=theLB: x.delete(ACTIVE))
theButton.pack()
mainloop()
但是有一个问题:Listbox 默认显示数量为10条,如果有超过10条的记录,该如何操作呢?
有两个方法:修改Listbox的height选项;添加Scrollbar 滚动条
Scrollbar 垂直滚动条
Scrollbar 滚动条虽然是一个单独组件,但是通常配合其他组件一起使用,起到辅助显示内容的作用
若要为某个组件安装垂直滚动条,需要以下两步:
- 设置该组件的yscrollbarcommand选项为Scrollbar组件的set()方法
- 设置Scrollbar 组件的command选项为该组件的yview()方法
参数 | 含义 |
---|---|
master | 代表了父窗口 |
bg | 背景色,如bg=”red”, bg="#FF56EF" |
relief | 指定外观装饰边界附近的标签,默认是平的,可以设置的参数:flat、groove、raised、ridge、solid、sunken |
width | 设置显示宽度,如果未设置此项,其大小以适应内容标签 |
bd | 设置Button的边框大小;bd(bordwidth)缺省为1或2个像素 |
示例:创建一个带有滚动条的Listbox
# p17_19.py
from tkinter import *
root = Tk()
sb = Scrollbar(root)
sb.pack(side=RIGHT, fill=Y)
lb = Listbox(root, yscrollcommand=sb.set) #设置yscrollcommand选项为Scrollbar的set()方法
for i in range(1000):
lb.insert(END, str(i))
lb.pack(side=LEFT, fill=BOTH)
sb.config(command=lb.yview) #设置comand参数为组件的yview()方法
mainloop()
设置滚动条属性为组件的yview()方法,表示:当用户操作滚动条时,滚动条触发组件的yview()方法,使内容滚动
设置组件属性为set()方法的含义表示:内容的滚动会调用Scrollbar的set()方法,使滚动条滚动到相应位置
Scale 滚动条
Scale与Scrollbar类似,但是不同的是,Scale是通过滑块表示某个范围的数值
参数 | 含义 |
---|---|
from_ | 设置该 Scale 的最小值(由于from是python关键字,故需要加下划线 from_) |
to | 设置该 Scale 的最大值 |
resolution | 设置该 Scale 滑动时的步长 |
label | 为 Scale 组件设置标签内容 |
length | 设置轨道的长度 |
width | 设置轨道的宽度 |
troughcolor | 设置轨道的背景色 |
sliderlength | 设置轨道的长度 |
sliderrelief | 设置滑块的立体样式 |
showvalue | 设置是否显示当前值 |
orient | 设置方向。该选项支持 VERTICAL 和 HORIZONTAL 两个值 |
digits | 设置有效数字至少要有几位 |
variable | 用于与变量进行绑定 |
command | 用于为该 Scale 组件绑定事件处理,函数或方法 |
示例:创建一个窗体,当单击按钮时,获取两个Scale组件的数值
from tkinter import *
root = Tk()
s1 = Scale(root, from_=0, to=42)
s1.pack()
s2 = Scale(root, from_=0, to=200, orient=HORIZONTAL)
s2.pack()
def show():
print(s1.get(), s2.get())
Button(root, text="获得位置", command=show).pack()
mainloop()
运行如下:
输出结果为:12 85
还可设置 resolution 控制分辨率(类似步长),设置 tickinterval 设置刻度
from tkinter import *
root = Tk()
#步长为5,刻度为5
Scale(root, from_=0, to=42, tickinterval=5, length=200, resolution=5, orient=VERTICAL).pack()
#步长为1,刻度为10
Scale(root, from_=0, to=200, tickinterval=10, length=600, orient=HORIZONTAL).pack()
mainloop()
Text 文本组件
Text 组件用于显示和处理多行文本,同样也可以作为简单的文本编辑器和网页浏览器
参数 | 含义 |
---|---|
background(bg) | 文本框背景色 |
foreground(fg) | 前景色 |
selectbackground | 选定文本背景色 |
selectforeground | 选定文本前景色 |
borderwidth(bd) | 文本框边框宽度 |
font | 字体 |
show | 文本框显示的字符,若为*,表示文本框为密码框 |
state | 状态 |
width | 文本框宽度 |
textvariable | 可变文本,与StringVar等配合着用 |
text 组件与 Entry 组件类似,创建时也是没有内容的,需要通过insert()方法来插入内容。而除了常规的文字内容外, text还可以插入window组件或者image图像
示例:
from tkinter import *
root = Tk()
text = Text(root, width=20, height=5)
text.pack()
text.insert(INSERT, "Hello everyone")
b1 = Button(text, text="ok")
text.window_create(INSERT, window=b1)
mainloop()
运行如下:
若需要在末尾创建图像,则使用 text.image_create(END , image=image)
Indexes 用法
Indexes表示索引,主要用于定位。Tkinter也提供了一系列的索引类型
- "line.column"(行.列)
表示第 line 行第 column 列,中间用”.“分隔行号列号,字符串或者浮点型都可识别。如”1.6“、2.5分别表示第1行第6列,第2行第5列。
需要注意的是:行号从1开始,列号从0开始,且若设置的行列号超过实际行列号,并不会报错,而是认为”已有内容末尾的下一个位置“
- "line.end"
表示该行最后一个字符。如获取第一行第2至最后一个字符:text.get(”1.2“,"1.end")
- INSERT(或insert)
插入光标的位置
- CURRENT(或current)
与鼠标坐标最接近的位置(若长按任一按钮,直到松开时才会响应)
- END(或end)
text文本缓冲区的最后一个位置的下一个位置
- user-defined marks
用户自定义的marks(marks见后文)
- User-defined tags
用户自定义的tags(tag见后文)
- selection(SEL_FIRST,SEL_LAST)
是一个特殊的tag,表示当前被选中的范围,可用SEL_FIRST、SEL_LAST表示该范围,若未选中内容,则抛出TclError异常
- window coordinate(@x,y)
使用窗口坐标作为索引,如在事件绑定中,可通过以下代码找到最接近鼠标的位置:
"@%d,%d" % (event.x,event.y)
用于指向在Text组件中嵌入的window和image对象
要引用一个window,只要简单地将一个Tkinter组件实例作为索引即可。
引用一个嵌入的image,只需使用相应的PhotoImage和BitmapImage对象
expression
用于修改任何格式的索引,是用字符串的形式实现修改索引的表达式。具体如下:
表达式 | 含义 |
---|---|
”+ count chars" | 将索引向前(右)移动count个字符。可以越过换行符,但是不能超过END的位置 |
”- count chars" | 将索引向后(左)移动count个字符。可以越过换行符,但是不能超过"1.0"的位置 |
”+ count lines" | 将索引向前(右)移动count行。索引会尽量保持与移动前在同一列,若移动后的行字符不够前一行,则移动至行尾 |
”- count lines" | 将索引向后(左)移动count行。索引会尽量保持与移动前在同一列,若移动后的行字符不够前一行,则移动至行尾 |
" linestarrt" | 将索引移动至当前索引行的行首。注:使用该表达式前需有一个空格隔开 |
" lineend | 将索引移动至当前索引行的行尾。注:使用该表达式前需有一个空格隔开 |
" wordstart" | 将索引移动到当前索引指向的单词的开头。单词的定义是:一系列字母、数字、下划线或任意非空白字符的组合。注:使用该表达式前需有一个空格隔开 |
" wordend" | 将索引移动到当前索引指向的单词的结尾。单词的定义是:一系列字母、数字、下划线或任意非空白字符的组合。注:使用该表达式前需有一个空格隔开 |
只要结果不产生歧义,可以缩写关键字及省略空格,如”+ 5 chars"可以简写为"+5c"
示例:删除光标前一个字符
def backspace(event):
event.widget.delete("%s-1c" % INSERT,INSERT)
Marks 用法
Mark(标记)通常是嵌入到Text组件中的不可见对象。text 默认包含3中marks:INSERT、CURRENT、user-defined marks
其中INSERT用于指定当前插入光标的位置,会绘制一个闪烁的光标(因此并非mark都不可见)
如果需在一个Mark前插入或删除文本,Mark会跟着一起移动。创建Mark需使用 mark_set()方法,删除Mark周围字符不会影响Mark
示例:插入语句“hello everyone”,将两个l中间的位置创建名为split的mark,并在该mark处插入空格
from tkinter import *
root = Tk()
text = Text(root, width=20, height=5)
text.pack()
text.insert(INSERT, "Hello everyone")
text.mark_set("split","1.3")
text.insert("split"," ")
mainloop()
运行如下:
删除自定义的Mark可使用mark_unset()方法,如删除上述的split标记 :text.mark_unset("split")
Tag用法
Tag(标签),通常用于改变Text组件中内容的样式和功能,可用来修改文本的字体、尺寸和颜色。另外,Tag 还允许将文本、嵌入的组件和图片与键盘和鼠标等事件相关联。
除了用户自定义的Tag,Tkinter还预设了一个特殊的Tag: SEL
创建Tag使用tag_add方法
示例:创建一个Tag1,内容为He、every,并设置为黄底蓝字
from tkinter import *
root = Tk()
text = Text(root, width=30, height=5)
text.pack()
text.insert(INSERT, "Hello everyone")
text.tag_add("tag1", "1.0", "1.2", "1.6","1.11")
text.tag_config("tag1", background="yellow", foreground="blue")
mainloop()
运行如下:
使用tag_config()方法可以设置Tag的样式,关于tag_config()方法的参数,在此不一一列举
若对同一个文本添加多个Tag,新的Tag会覆盖旧的Tag,可以使用tag_raise()、lower()方法提升或降低Tag的优先级。
如降低名为 split 的tag的优先级:text.tag_lower("split")
除了修改格式,Tag还可以进行事件绑定。绑定事件时使用tag_bind()方法
示例:当鼠标进入every文本段时,鼠标样式切换为“arrow”形态,离开时切换回“xtrem”
from tkinter import *
root = Tk()
text = Text(root, width=30, height=5)
text.pack()
text.insert(INSERT, "Hello everyone")
text.tag_add("tag1", "1.6", "1.11")
text.tag_config("tag1", foreground="red")
def show_hand_cursor(event):
text.config(cursor="arrow")
def show_arrow_cursor(event):
text.config(cursor="xterm")#xterm
text.tag_bind("tag1", "<Enter>", show_hand_cursor)
text.tag_bind("tag1", "<Leave>", show_arrow_cursor)
mainloop()
运行如下:
部分Text技巧
(1)判断内容是否变化
如关闭时判断内容是否进行修改,若修改则提醒。可通过Text组件中文本的MD5来判断内容是否变化。
使用MD5时,需要导入 hashlib 模块,再将文本内容传入
示例:创建一个getSig函数,获取文本的MD5值
import hashlib
def getSig(content):
m = hashlib.md5(content)
return m.digest()
(2)查找内容
使用search()方法可以搜索Text组件中的内容,可以提供一个确切的目标进行搜索(默认),也可以使用Tcl格式的正则表达式进行搜索(需设置 regexp 选项为True)。如在全文中查找目标文本:pos = text.search("目标文本",start,stopindex=END)
如果忽略stopindex选项,表示到末尾,若设置backwords为True,表示修改搜索方向为向后搜索。此时start应为END
(3)撤销、恢复操作
使用text.undo()表示撤销
使用text.redp()表示恢复
撤销和恢复只能处理一次“操作”,那么什么样的算一次“操作”呢?
默认操作:焦点切换、按下回车键、删除/插入操作的转换
那么,自定义“插入一个字符”算一个操作,使用撤销/恢复时操作也是处理一个字符。那么需要绑定键盘事件,在事件触发时,插入一个“分隔符”表示分隔操作。插入分隔符,可使用edit_separator()方法
示例:
from tkinter import *
root = Tk()
text = Text(root, width=30, height=5, autoseparators=False, undo=True, maxundo=10)
text.pack()
def callback(event):
text.edit_separator()
text.bind('<Key>', callback)
text.insert(INSERT, "Hello everyone")
def show():
text.edit_undo()
Button(root, text="撤销", command=show).pack()
mainloop()
运行如下:
Canvas 绘图
Canvas 通常用于显示和绘制图形,可以通过它回值直线、圆形、多边形甚至是其他组件
参数 | 含义 |
---|---|
background(bg) | 背景色 |
foreground(fg) | 前景色 |
borderwidth | 组件边框宽度 |
width | 组件宽度 |
height | 高度 |
bitmap | 位图 |
image | 图片 |
在Canvas组件上绘制对象,可以用create_xxx()方法(xxx表示对象类型,如直线line,矩形rectangle,文本text等)
示例:创建一个蓝色的矩形:
from tkinter import *
root = Tk()
w = Canvas(root, width=200, height=100)
w.pack()
w.create_rectangle(50, 25, 150, 75, fill="blue")
mainloop()
运行如下:
绘制矩形时,4个位置参数分别表示:左上角点的x、左上角点的y、右下角点的x、右下角点的y。
那么,绘制一个圆形呢?这时就需要用到create_oval()
from tkinter import *
root = Tk()
w = Canvas(root, width=200, height=100)
w.pack()
w.create_oval(70,20,130,80)
mainloop()
运行如下:可以发现,绘制一个圆也是指定左上角右下角的点坐标。通过更改坐标可以绘制任意形状的圆、椭圆
那么,绘制一个多边形,则需要使用create_polygon(),以绘制一个国旗上的五角星为例:
from tkinter import *
import math as m
root = Tk()
w = Canvas(root, width=200, height=100, background="red")
w.pack()
center_x = 100
center_y = 50
r = 50
points = [
# 左上点
center_x - int(r * m.sin(2 * m.pi / 5)),
center_y - int(r * m.cos(2 * m.pi / 5)),
# 右上点
center_x + int(r * m.sin(2 * m.pi / 5)),
center_y - int(r * m.cos(2 * m.pi / 5)),
# 左下点
center_x - int(r * m.sin(m.pi / 5)),
center_y + int(r * m.cos(m.pi / 5)),
# 顶点
center_x,
center_y - r,
# 右下点
center_x + int(r * m.sin(m.pi / 5)),
center_y + int(r * m.cos(m.pi / 5)),
]
w.create_polygon(points, outline="yellow", fill="yellow")
mainloop()
运行如下:
由于五角星涉及三角函数,故需要导入math模块。
由此,可以发现:向Canvas传递位置参数时,可以是一个一个参数,也可以是由参数组成的列表或者元组。参数分别表示第一个点的xy,第二个点的xy……
既然存在画布工具,那么可不可以做到鼠绘呢?很显然,不能,因为Tkinter并没有提供自由画点的方法。所以只能偷天换日——画一个极小的圆代替点。此时,为了获取鼠标轨迹,就需要绑定事件了:
from tkinter import *
root = Tk()
w = Canvas(root, width=400, height=200)
w.pack()
def paint(event): #获取鼠标在组件内移动的x,y
x1, y1 = (event.x - 1), (event.y - 1)
x2, y2 = (event.x + 1), (event.y + 1)
w.create_oval(x1, y1, x2, y2, fill="black")
w.bind("<B1-Motion>", paint) #绑定事件:按住鼠标左键时在组件内移动的轨迹
Label(root, text="按住鼠标左键并移动即可开始自由绘制").pack(side=BOTTOM)
mainloop()
运行如下:
由于每次画点都是通过事件触发,每次事件触发的时间间隔基本固定,因此绘制的图像类似于打点计时器绘制的图像,速度快的地方点少,速度慢的地方点多。
Canvas组件支持的对象
- arc(弧形、弦或扇形)
- bitmap(内建的位图文件或XBM格式的文件
- image(BitmapImage或PhotoImage的实例对象
- line(线)
- oval(圆形或椭圆形)
- polygon(多边形)
- rectangle(矩形)
- text(文本)
- window(组件)
其中,弦、扇形、椭圆形、圆形、多边形和矩形这些“封闭式”图形都是由轮廓线和填充颜色组成,可通过outline和fill选项设置他们的颜色,还可以设置为透明(传入空字符)
坐标系
由于画布可能比窗口大(带有滚动条),因此Canvas组件可以选择使用两种坐标系:
窗口坐标系:以窗口的左上角为坐标原点
画布坐标系:以画布的左上角为坐标原点
画布对象显示的顺序
在画布中创建的画布对象都会被列入显示列表中,下方的图形越接近背景。这一点有点像PS中的图层,新创建的图像会显示在旧图像的上层,在图层关系中也是上层。当然,组件中的显示列表也和图层一样,可以被重新排序
指定画布对象
Canvas组件提供几种方法来指定画布对象
- Item handles
- Tags
- ALL
- CURRENT
Item handles是一个用于指定某个画布对象的整型数(也称画布对象的ID)。当在Canvas组件上创建一个画布对象的时候,Tkinter将自动为其指定一个在Canvas中独一无二的整型值,然后各种Canvas方法可以通过这个值操纵该画布对象。
Tag是附在画布对象上的标签,Tag由普通的非空白字符串组成。一个画布对象可以与多个Tag相关联,一个Tag也可以用于描述多个画布对象。然而,与Text组件不同,没有指定画布对象的tag不能进行事件绑定和配置样式。即Canvas组件的Tag仅为画布对象所有。
Canvas预设了两个Tags:ALL和CURRENT
- ALL(或“all”)表示Canvas中的所有画布对象
- CURRENT(或“current”)表示鼠标指针下的画布对象
Menu 菜单
用于实现顶级菜单、下拉菜单和弹出菜单
函数 | 描述 |
---|---|
bg | 背景色,如bg=”red”, bg="#FF56EF" |
fg | 前景色,如fg=”red”, fg="#FF56EF" |
font | 字体及大小,如font=("Arial", 8),font=("Helvetica 16 bold italic") |
relief | 指定外观装饰边界附近的标签,默认是平的,可以设置的参数:flat、groove、raised、ridge、solid、sunken |
selectcolor | 设置选中区的颜色 |
bd | 设置Checkbutton的边框大小;bd(bordwidth)缺省为1或2个像素 |
创建顶级菜单时,创建的也是空白组件,需要通过add_command()方法添加顶级菜单。
而创建下拉菜单,需要先创建下拉菜单,再在将其绑定在顶级菜单中
如:创建开始、编辑菜单,下拉菜单中各有3个选项,第一个下拉菜单每个选项中添加一个分割线,第二个下拉菜单在与顶级菜单分界处创建横线分割线
from tkinter import *
root = Tk()
menubar = Menu(root)
# 创建一个下拉菜单“文件”,然后将它添加到顶级菜单中
filemenu = Menu(menubar, tearoff=False)
items=['打开','保存','另存为']
for item in items:
filemenu.add_command(label=item)
filemenu.add_separator()
menubar.add_cascade(label="开始", menu=filemenu)
# 创建另一个下拉菜单“编辑”,然后将它添加到顶级菜单中
editmenu = Menu(menubar, tearoff=True)
items = ['插入','删除','复制']
for item in items:
editmenu.add_command(label=item)
menubar.add_cascade(label="编辑", menu=editmenu)
# 显示菜单
root.config(menu=menubar)
运行如下:
在代码中实例化了两次Menu,还出现了不一样的代码。为了便于理解,绘制一个示意图,表示整个Menu的结构
第一次实例化创建的是一个空白导航栏,第二次实例化创建的是空白下拉菜单。对下拉菜单添加完按钮后,将其指定给导航栏的某个标签(同时创建该标签)。最后通过root.config()指定显示哪个导航栏(若创建了多个导航栏)。
示例:创建一个可切换的导航栏,单击第一个标签下拉菜单的【转换】按钮,切换至另一个导航栏
from tkinter import *
root = Tk()
root.title("First")
menubar = Menu(root)
menubar2 = Menu(root)
def call1():
root.title("First")
root.config(menu=menubar)
def call2():
root.title("Second")
root.config(menu=menubar2)
# 创建一个带转换按钮的导航栏
changemenu = Menu(menubar, tearoff=False)
item='转换'
changemenu.add_command(label=item,command=call2)
menubar.add_cascade(label="操作", menu=changemenu)
filemenu = Menu(menubar, tearoff=False)
items=['打开','保存','另存为']
for item in items:
filemenu.add_command(label=item)
menubar.add_cascade(label="文件", menu=filemenu)
editmenu = Menu(menubar, tearoff=False)
items = ['插入','删除','复制']
for item in items:
editmenu.add_command(label=item)
menubar.add_cascade(label="编辑", menu=editmenu)
changemenu = Menu(menubar2, tearoff=False)
item='转换'
changemenu.add_command(label=item,command=call1)
menubar2.add_cascade(label="操作", menu=changemenu)
othermenu = Menu(menubar2, tearoff=False)
items = ['帮助','升级','关于']
for item in items:
othermenu.add_command(label=item)
menubar2.add_cascade(label="其他", menu=othermenu)
# 显示菜单
root.config(menu=menubar)
mainloop()
运行如下:
除了向下拉菜单中添加自带选项之外,还可以添加单选、复选按钮。自带特殊函数如下:
函数 | 含义 |
---|---|
menu.add_cascade | 添加子选项 |
menu.add_command | 添加命令(label参数为显示内容) |
menu.add_separator | 添加分隔线 |
menu.add_checkbutton | 添加确认按钮 |
delete | 删除 |
Menubutton
该按钮可以在窗体其他位置创建菜单按钮,而不仅仅在顶级菜单中。创建方法与Menu的顶级菜单类似,代替了导航栏的位置。
示例:
from tkinter import *
root = Tk()
def callback():
print("~被调用了~")
mb = Menubutton(root, text="点我", relief=RAISED)
mb.pack()
filemenu = Menu(mb, tearoff=False)
filemenu.add_checkbutton(label="打开", command=callback, selectcolor="yellow")
filemenu.add_command(label="保存", command=callback)
filemenu.add_separator()
filemenu.add_command(label="退出", command=root.quit)
mb.config(menu = filemenu)
mainloop()
运行如下:
OptionMenu 选项菜单
该组件是下拉菜单的改版,同样弥补了Listbox无法实现下拉列表框的缺陷。创建时需要创建一个Variable类变量,用于记录用户的选择。
示例:
from tkinter import *
root = Tk()
variable = StringVar()
variable.set("one")
w = OptionMenu(root, variable, "one", "two", "three")
w.pack()
mainloop()
print(variable.get())
运行如下:
若要获取用户的选择,对变量使用get()方法即可
Message 消息组件
该组件是Label的变体,用于显示多行文本,可以自动换行,并调整文本的尺寸使其适应给定的尺寸
示例:
from tkinter import *
root = Tk()
w1 = Message(root, text="下面插播一条新闻", width=100)
w1.pack()
w2 = Message(root, text="这条新闻超级的长长长长长长长长长长", width=100)
w2.pack()
mainloop()
Spinbox 组件
该组件是TK8.4新增的组件,算是Entry的变体,类似于Scale与Entry组件的结合,使用时有点像Excel的数据有效性,用于从一些固定的值中选取一个。
Spinbox的用法与Entry非常相似,主要区别是Spinbox可以通过范围或者元组指定用户输入的内容
示例:创建一个男女信息框
from tkinter import *
root = Tk()
sb1=Spinbox(root,from_=0,to=1,value=("男","女"))
sb2=Spinbox(root,value=("男","女"))
sb1.pack()
sb2.pack()
mainloop()
运行如下:
若同时指定(from_,to)和value参数,如:
sb1=Spinbox(root,from_=0,to=1,value=("男","女"))
则value参数指定的范围会覆盖(from_,to)指定的范围
PanedWindow 组件
是TK8.4新增的组件,是一个空间管理器。与Frame类似,都是为组件提供一个框架,不过该组件允许用户调整程序的空间范围。
示例:创建一个PanedWindow组件,将空间分为两部分
from tkinter import *
m = PanedWindow(orient=VERTICAL)
m.pack(fill=BOTH, expand=1)
top = Label(m, text="top pane")
m.add(top)
bottom = Label(m, text="bottom pane")
m.add(bottom)
mainloop()
运行如下:
分割线默认是不显示的。可以设置sashrelief参数设置为SUNKEN,将showhandle参数设置为True则可以添加一个手柄(handle)
示例:添加横竖两个iPanedWindow组件,分隔空间为3部分,使分割线显示并添加手柄
from tkinter import *
m1 = PanedWindow(showhandle=True, sashrelief=SUNKEN)
m1.pack(fill=BOTH, expand=1)
left = Label(m1, text="left pane")
m1.add(left)
m2 = PanedWindow(orient=VERTICAL, showhandle=True, sashrelief=SUNKEN)
m1.add(m2)
top = Label(m2, text="top pane")
m2.add(top)
bottom = Label(m2, text="bottom pane")
m2.add(bottom)
mainloop()
运行如下:分隔三部分,可以先分为两部分,再添加一条线,分隔成三部分,如图
Toplevel 顶级窗口
该组件类似于Frame组件,但是该组件有独立的标题栏、边框等部件,类似于弹窗,或者称子窗体。
主要用于显示额外的窗口、对话框和其他弹出窗口
示例:创建一个按钮,单击一次创建一个Toplevel 弹窗
from tkinter import *
root = Tk()
def create():
top = Toplevel()
top.title("示例")
msg = Label(top, text="这是一个Toplevel")
msg.pack()
Button(root, text="创建", command=create).pack()
mainloop()
运行如下:
若想获取和设置Toplevel的窗口属性,可以通过attributes()方法。若只设置属性名,则返回当前窗口该属性值;若设置属性名和值,则修改窗口的属性值
示例:将Toplevel的窗口设置为50%透明
from tkinter import *
root = Tk()
def create():
top = Toplevel()
top.title("示例")
top.attributes("-alpha", 0.5)
msg = Message(top, text="这是一个Toplevel")
msg.pack()
Button(root, text="创建Toplevel", command=create).pack()
mainloop()
事件
事件绑定
事件,是执行某一操作时触发的事情。如:人饿的时候吃饭会饱,吃饭是操作,执行吃饭的操作时,饥饿感和饱腹感都在不断变化,相当于“吃饭”操作触发了“修改人的饥饿感属性和饱腹感属性”的事件。
一个Tkinter程序大部分事件都花在事件循环中(通过maxinloop()方法进入循环)。事件可以有各种来源,包括用户触发的鼠标、键盘操作和窗口管理器触发的重绘事件(绝大多数情况下都是由用户间接引起的)。
Tkinter提供一个强大的机制可以自由地处理事件:对每个组件来说,可通过bind()方法将函数或方法绑定到具体的事件上。当被处罚的事件满足该组件绑定的事件时,Tkinter就会带着事件描述去调用handler()方法。
示例:捕获键盘敲击位置
from tkinter import *
root = Tk()
def callback(event):
print("敲击位置:", repr(event.char))
frame = Frame(root, width=200, height=200)
frame.bind("<Key>", callback)
frame.focus_set() #使组件获得焦点
frame.pack()
mainloop()
运行如下:
注:键盘事件需要组件获得焦点才能接收,故需要用focus_set()方法使组件获得焦点
根据上述示例,可以大致归纳出绑定事件的基本步骤:
- 创建事件触发时的操作(指定的函数或方法)
- 创建组件
- 组件.bind(事件类型,触发时的操作)
- 组件.focus_set()(获取焦点,若不需要获取焦点就能捕捉事件则不用这句)
- mainloop()
事件序列
Tkinter可以使用事件序列的机制来自定义事件,只需要用bind()方法将具体的事件序列与自定义的方法绑定即可。
事件序列以字符串的形式表示,可以表示一个或多个相关联的事件(若为多个事件,需要满足所有事件条件才会调用)。
事件序列的语法为:<modifier-type-detail>
- 事件序列包含在尖括号<>中
- type部分的内容是最重要的,用于描述普通的事件类型,如单击鼠标单击键盘等
- modifier部分是可选的,通常用于描述组合键,如:Ctrl+C,Shift+单击
- detail部分是可选的,通常用于描述具体的按键,如:Button-1表示鼠标左键
语法示例:
<Button-1> 表示用户单击左键
<KeyPress-H> 表示用户单击H案件
<Control-Shift-KeyPress-H> 表示用户同时单击Ctrl+Shift+H
type部分常用关键词及含义:
type关键词 | 含义 |
---|---|
Activate | 当组件的状态从“未激活”变为“激活”的时候触发事件 |
Button | 当用户单击鼠标按键时触发事件。detail部分指定具体哪个按键:<Button-1>鼠标左键,<Button-2>鼠标中建,<Button-3>鼠标右键,<Button-4>滚轮上滚(Linux),<Button-5>滚轮下滚(Linux)。 |
ButtonRelease | 当用户释放鼠标按键的时候触发事件。在大多数情况下,比Button更好用,因为当用户不小心按下鼠标,用户可以将鼠标移出组件再释放鼠标,从而避免不小心触发事件 |
Configure | 当组件的尺寸发生改变的时候触发事件 |
Deactivate | 当组建的状态从“激活”变为“未激活的时候触发事件 |
Destroy | 当组件被小伙的时候触发事件 |
Enter | 当鼠标指针进入组件的时候触发事件。注意:不是指用户按下回车键 |
Expose | 当窗口或组件的某部分不再被覆盖的时候触发事件 |
FocusIn | 当组件获得焦点的时候触发事件。用户可以用Tab键将焦点转移到该组件上(需要该组件的takefocus选项为True);也可以调用focus_set()方法使该组件获得焦点 |
FocusOut | 当组件失去焦点的时候触发事件 |
KeyPress | 当用户按下键盘按键的时候触发事件。detail可以指定具体的按键,例如<KeyPress-H>表示当大写字母H被按下的时候触发事件。KeyPress可以简写为Key |
KeyRElease | 当用户释放键盘按键的时候触发事件 |
Leave | 当鼠标指针离开组件的时候触发事件 |
Map | 当组件被映射的时候触发事件。意思是在应用程序中显示该组件的时候触发事件,例如调用grid()方法 |
Motion | 当鼠标在组件内移动的整个过程均触发事件 |
MouseWheel | 当鼠标滚轮滚动的时候触发事件。目前仅支持Windows和Mac系统,Linux请参考Button |
Unmap | 当组件被取消映射的时候触发事件。指在应用成组中不再显示该组件的时候触发事件,例如调用grid_remove()方法 |
Visibility | 当应用程序至少有一部分在屏幕中是可见的时候触发事件 |
modifier部分常用的关键词及含义
关键词 | 含义 |
---|---|
Alt | 当按下Alt按键的时候触发事件 |
Any | 表示任何类型的按键被按下的时候触发事件。例如<Any-KeyPress>表示当用户按下任何按键时触发事件 |
Control | 当按下Ctrl按键的时候触发事件 |
Double | 当后续两个事件被连续触发的时候触发事件。例如<Double-Button-1>表示当用户双击时触发事件 |
Lock | 当打开大写字母锁定键(CapsLock)的时候触发按键 |
Shift | 当按下Shift按键的时候触发事件 |
Triple | 与Double类似,当后续三个事件被连续触发的时候触发事件 |
Event对象
当Tkinter回调预先定义的函数时,将带着Event对象(作为参数)去调用。
Event对象的属性及含义:
属性 | 含义 |
---|---|
widget | 产生该事件的组件 |
x, y | 当前的鼠标位置坐标(相对于窗口左上角,以像素为单位) |
x_root, y_root | 当前的鼠标位置坐标(相对于屏幕左上角,以像素为单位) |
char | 按键对应的字符(键盘事件专属) |
keysym | 按键名(键盘事件专属) |
keycode | 按键码(键盘事件专属) |
num | 按钮数字(鼠标事件专属) |
width, height | 组件的新尺寸(Configure 事件专属)) |
type | 该事件的类型 |
当事件为<Key><KeyPress><KeyRelease>时,detail可通过设定具体的按键名keysym来达到筛选的目的。
键盘所有特殊案件的keysym和keycode:
按键名(keysym) | 按键码(keycode) | 含义 |
---|---|---|
Alt_L | 64 | 左边的 Alt 键 |
Alt_R | 113 | 右边的 Alt 键 |
BackSpace | 22 | BackSpace(退格)键 |
Cancel | 110 | break 键 |
Caps_Lock | 66 | CapsLock |
Control_L | 37 | 左边的 Ctrl 键 |
Control_R | 109 | 右边的 Ctrl 键 |
Delete | 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 | 90 | 小键盘 0 |
KP_1 | 87 | 小键盘 1 |
KP_2 | 88 | 小键盘 2 |
KP_3 | 89 | 小键盘 3 |
KP_4 | 83 | 小键盘 4 |
KP_5 | 84 | 小键盘 5 |
KP_6 | 85 | 小键盘 6 |
KP_7 | 79 | 小键盘 7 |
KP_8 | 80 | 小键盘 8 |
KP_9 | 81 | 小键盘 9 |
KP_Add | 86 | 小键盘 + |
KP_Begin | 84 | 小键盘 中间键(5) |
KP_Decimal | 91 | 小键盘 . |
KP_Delete | 91 | 小键盘 Delete |
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_Multiply | 63 | 小键盘 * |
KP_Next | 89 | 小键盘 PaageDown |
KP_Prior | 81 | 小键盘 PageUp |
KP_Right | 85 | 小键盘 → |
KP_Subtract | 82 | 小键盘 - |
KP_Up | 80 | 小键盘 ↑ |
Next | 105 | PageDwon 键 |
Num_Lock | 77 | Num_Lock(数字锁定) 键 |
Pause | 110 | Pause(暂停) 键 |
| 111 | PrintScm(打印屏幕) 键 |
Prior | 99 | PAgeUP 键 |
Return | 36 | Enter(回车)键 |
Right | 102 | → 键 |
Scroll_Lock | 78 | Scroll_Lock 键 |
Shift_L | 50 | 左边的 Shift 键 |
Shift_R | 62 | 右边的 Shift 键 |
Tab | 23 | Tab 键 |
Up | 98 | ↑键 |
标准对话框
messagebox 消息对话框
使用函数 | 对话框样式 |
---|---|
askokcancle() | |
askquestion() | |
askretrycancel() | |
askyesno() | |
showerror() | |
showinfo() | |
showwarning() |
所有函数都有相同的参数:title、message、options
title:设置标题栏的文本内容
message设置对话框的主要文本内容,可以用’\n’来实现换行
options参数设置内容见下表
options参数设置内容
options选项
含义
default
设置默认的按钮(直接回车时相应的按钮),默认是第一个按钮
icon
指定对话框显示的图标,可以是error、INFO、QUESTION、WARNING。但是不能是自己的图标
parent
如果不指定该选项,那么对话框默认显示在根窗口上
如果想要将对话框显示在子窗口w上,设置parnet=w
关于parent需要注意的是:如果未指定parent参数,也未创建一个任何一个窗体,使用上述函数
生成messagebox时,会自动创建一个空白的Tk窗体,产生的效果与实例化Tk()相同。空白Tk窗体如下:
而如果parent参数设置的是Tk类下的子窗体,如Toplevel,则会创建两个空白tk窗体,一个表示Tk窗体,一个表示Toplevel窗体。运行如下:
窗体间的结构大致如下:
若关闭Toplevel,则会同时关闭messagebox;若关闭Tk,则会将Toplevel、messagebox一同关闭,因为他们都是基于Tk创建的子窗体。
但是,当直接关闭Tk时,会出现AttributeError: 'NoneType' object has no attribute 'tk'异常;关闭Toplevel再关闭Tk或从messagebox开始从上往下关闭,则不会出现该异常。
返回值
askokcancel()、askretrycancel()和askyesno()返回bool类型值:
- 返回True表示用户单击了“确定“或”是“按钮
- 返回False表示用户单击了“取消“或”否:按钮
askquestion()返回yes或no字符串表示用户单击了“是”或:否“按钮
showerror(),showinfo()或showwarning()返回ok表示用户按下了“是“按钮
fieldialog 文件对话框
示例:打开文件,并获取路径
from tkinter import *
import tkinter.filedialog
root = Tk()
def callback():
fileName = tkinter.filedialog.askopenfilename()
print(fileName)
Button(root, text="打开文件", command=callback).pack()
mainloop()
运行如下:
注:若没有import tkinter.filedialog 语句,则会出现错误:NameError: name 'filedialog' is not defined
filedialog模块提供以下函数
filedialog 内置函数
函数
含义
askopenfile()
生成打开单个文件的对话框,返回所选择文件的文件流
askopenfiles()
生成打开多个文件的对话框,返回多个所选择文件的文件流组成的列表
askopenfilename()
生成打开单个文件的对话框,返回所选择文件的文件路径
askopenfilenames()
生成打开多个文件的对话框,返回多个所选择文件的文件路径组成的元组
asksaveasfile()
生成保
运行如下:
注:若没有import tkinter.filedialog 语句,则会出现错误:NameError: name 'filedialog' is not defined
filedialog模块提供以下函数:
函数 | 含义 |
askopenfile() | 生成打开单个文件的对话框,返回所选择文件的文件流 |
askopenfiles() | 生成打开多个文件的对话框,返回多个所选择文件的文件流组成的列表 |
askopenfilename() | 生成打开单个文件的对话框,返回所选择文件的文件路径 |
askopenfilenames() | 生成打开多个文件的对话框,返回多个所选择文件的文件路径组成的元组 |
asksaveasfile() | 生成保存文件的对话框,返回所选择文件的文件输出流 |
asksaveasfilename() | 生成保存文件的对话框,返回所选择文件的文件路径 |
askdirectory() | 生成打开目录的对话框 |
两个函数可供设置的参数是一样的,参数如下
参数 | 含义 |
defaultextension | 指定文件的后缀,例如defaultextension=“.jpg“,当用户输入一个文件名是,会自动添加.jpg后缀 注:若输入的文件名包含后缀,则该选项不生效 |
filetypes | 指定筛选文件类型的下拉菜单选项,该选项的值是由2元组构成的列表。每个2元组由(类型名,后缀名)构成,如:filetypes=[(“PNG”,”.png”),(“JPG”,”.jpg”)] |
initialdir | 指定打开/保存文件的默认路径,默认路径是当前文件夹 |
initialfile | 指定所选择的文件 |
parent | 如果不指定该选项,那么对话框默认显示在根窗口上 如果想要将对话框显示在子窗口w上,设置parent=w |
title | 指定文件对话框的标题栏文本 |
multiple | 指定是否允许多选 |
对于打开目录的对话框,还额外支持一个 mustexist 选项,该选项指定是否只允许打开己存在的目录
返回值
- 如果用户选择了一个文件,那么返回值是该文件的完整路径
- 如果用户单击了“取消“按钮,那么返回值是空字符串
的对话框,返回所选择文件的文件输出流
asksaveasfilename()
生成保存文件的对话框,返回所选择文件的文件路径
askdirectory()
生成打开目录的对话框
这些函数可供设置的参数基本上是一样的,参数如下
filedialog 参数汇总
参数
含义
defaultextension
指定文件的后缀,例如defaultextension=“.jpg“,当用户输入一个文件名是,会自动添加.jpg后缀
注:若输入的文件名包含后缀,则该选项不生效
filetypes
指定筛选文件类型的下拉菜单选项,该选项的值是由2元组构成的列表。每个2元组由(类型名,后缀名)构成,如:filetypes=[(“PNG”,”.png”),(“JPG”,”.jpg”)]
initialdir
指定打开/保存文件的默认路径,默认路径是当前文件夹
initialfile
指定所选择的文件
parent
如果不指定该选项,那么对话框默认显示在根窗口上
如果想要将对话框显示在子窗口w上,设置parent=w
title
指定文件对话框的标题栏文本
multiple
指定是否允许多选
注:对于打开目录的对话框,还额外支持一个 mustexist 选项,该选项指定是否只允许打开己存在的目录
返回值
- 如果用户选择了一个文件,那么返回值是该文件的完整路径
- 如果用户单击了“取消“按钮,那么返回值是空字符串