上一篇:Python tkinter(GUI编程)模块全解(中)_Python zzy的博客-CSDN博客
Canvas是画布组件,用户可以在上面绘制图形、图像、文本、组件,还可以使上面的绘制对象移动。
参考资料:Python ---(十一)Tkinter窗口组件:Canvas_近视的脚踏实地的博客-CSDN博客
Canvas(master=None, cnf={}, **kw)
参数 | 作用 |
highlightthickness | 设置高亮边框的宽度;这个参数大部分组件都有,这里提出来需要强调的是,Canvas是有highlightthickness的,这使得有时边框会变色,影响效果,所以每次建立Canvas的时候最好设为0 |
scrollregion | 设置Canvas的滚动范围,格式是(x1, y1, x2, y2),代表左上角坐标和右下角坐标构成的一个矩形,如果不指定无法正常使用滚动条 |
confine | 是否允许滚动超过scrollregion指定的范围,默认为True |
xscrollcommand | x方向滚动 |
yscrollcommand | y方向滚动 |
xscrollincrement | x方向滚动步长,如"2c"表示2厘米,可选单位有"c"(厘米), "i"(英寸), "m"(毫米), "p"(DPI) |
yscrollincrement | y方向滚动步长,格式同xscrollincrement |
常用方法:
方法 | 作用 |
addtag_above(newtag, tagOrId) | 为tagOrld上方的画布对象添加tag |
addtag_all(newtag) | 为画布中所有的对象添加tag |
addtag_below(newtag, tagOrId) | 为tagOrld下方的画布对象添加tag |
addtag_closest(newtag, x, y, halo=None, start=None) | 以(x, y)为中心,为距离在halo之内的画布对象添加tag;如果指定start(一个画布对象),那么该方法将为低于但最接近该对象的画布对象添加tag |
addtag_enclosed(newtag, x1, y1, x2, y2) | 为(x1, y1, x2, y2)矩形范围里面的画布对象添加tag(画布对象必须完全位于矩形范围之内) |
addtag_overlapped(newtag, x1, y1, x2, y2) | 为(x1, y1, x2, y2)矩形范围里面的画布对象添加tag(画布对象不一定完全位于矩形范围之内,有一部分在矩形范围内也行) |
addtag_withtag(self, newtag, tagOrId) | 为画布对象添加tag,如果画布对象已经有tag,那么所有拥有该tag的画布对象重新添加一个新的tag;如果画布对象没有tag,那么则为此对象添加一个tag |
bbox(*args) | 返回一个四元组(x1, y1, x2, y2)用于描述args指定的画布对象所在的矩形范围 |
canvasx(screenx, gridspacing=None) | 将窗口x坐标转换成画布上的x坐标 |
canvasy(screeny, gridspacing=None) | 将窗口y坐标转换成画布上的y坐标 |
coords(*args) | 如果只提供画布对象作为参数,则返回画布对象的位置(x1, y1, x2, y2);如果提供coords(tagOrId, x1, y1, x2, y2),则将tagOrId画布对象的位置移动到(x1, y1, x2, y2) |
create_arc(*args, **kw) | 绘制弧形、弓形或扇形,并返回该画布对象的id |
create_bitmap(*args, **kw) | 绘制位图,并返回该画布对象的id |
create_image(*args, **kw) | 绘制图片,并返回该画布对象的id(图片对象的名称) |
create_line(*args, **kw) | 绘制一条或多条线段,并返回该画布对象的id |
create_oval(*args, **kw) | 绘制椭圆,并返回该画布对象的id |
create_polygon(*args, **kw) | 绘制多边形,并返回该画布对象的id |
create_rectangle(*args, **kw) | 绘制矩形,并返回该画布对象的id |
create_text(*args, **kw) | 绘制文字,并返回该画布对象的id |
create_window(*args, **kw) | 绘制组件,并返回该画布对象的id(组件对象的名称) |
delete(*args) | 删除画布对象 |
dtag(*args) | 需指定画布对象,以及需要删除的tag,如果不指定需要删除的tag,则在该画布对象中移除所有的tag |
find_above(tagOrId) | 返回在tagOrId之上的画布对象id |
find_all() | 返回画布上所有对象的id元组 |
find_below(tagOrId) | 返回在tagOrId之下的画布对象id |
find_closest(x, y, halo=None, start=None) | 返回接近(x, y)的画布对象元组 |
find_enclosed(x1, y1, x2, y2) | 返回完全位于(x1, y1, x2, y2)之内的画布对象 |
find_overlapping(x1, y1, x2, y2) | 返回与(x1, y1, x2, y2)位置有接触的画布对象 |
find_withtag(tagOrId) | 返回tagOrId指定的画布对象id |
focus(tagOrId) | 将画布焦点转移到tagOrId |
gettags(tagOrId) | 返回tagOrId画布对象的所有tag |
itemcget(tagOrId, option) | 返回tagOrId画布对象option选项的值 |
itemconfig(tagOrId, cnf={}, **kw) | 设置tagOrId的选项值 |
move(tagOrId, x, y) | 将tagOrId在x方向上移动x个像素,在y方向上移动y个像素 |
postscript(cnf={}, **kw) | 将画布内容封装成PostScript |
scale(tagOrId, xOrigin, yOrigin, xScale, yScale) | 对tagOrId对象进行缩放,xOrigin和yOrigin指定缩放位置,xScale和yScale指定缩放比例 |
tag_bind(tagOrId, sequence=None, func=None, add=None) | tagOrId绑定事件 |
tag_unbind(self, tagOrId, sequence, funcid=None) | tagOrId解除事件绑定 |
tag_lower(*args) | 将一个或多个画布对象置于底部 |
tag_raise(*args) | 将一个或多个画布对象置顶 |
type(tagOrId) | 返回tagOrId的绘制类型,有“arc”, “bitmap”, “image”, “line”, “oval”, “polygon”, “rectangle”, “text”, 或 “window” |
create_arc方法用来绘制扇形,弓形或弧形。首先需传递四个参数代表(x1, y1, x2, y2)。下面是**kw选项。
from tkinter import *
root = Tk()
cv = Canvas(root, bg="white", highlightthickness=0)
cv.pack()
cv.create_arc(0, 10, 100, 100, style="pieslice")
cv.create_arc(100, 10, 200, 100, style="chord")
cv.create_arc(200, 10, 300, 100, style="arc")
mainloop()
运行效果:
create_bitmap用于绘制一个位图。首先需传递绘制的位置x, y。
参数 | 作用 |
bitmap | 指定位图的名称 |
background | 位图的背景色 |
foreground | 位图的前景色 |
state | 画布对象状态 |
tags | 画布对象标签 |
from tkinter import *
root = Tk()
cv = Canvas(root, bg="white", highlightthickness=0)
cv.pack()
cv.create_bitmap(100, 100, bitmap="info", foreground="red", background="yellow")
mainloop()
create_image方法用于绘制图片。首先需指定图片的位置x, y。
参数 | 作用 |
image | 指定显示的图片 |
state | 画布对象状态 |
tags | 画布对象标签 |
from tkinter import *
root = Tk()
cv = Canvas(root, bg="white", highlightthickness=0)
cv.pack()
image = PhotoImage(file="monster.png")
cv.create_image(100, 100, image=image)
mainloop()
create_line方法用于绘制线条。需先给定一系列参数表示一系列点的位置,如0, 0, 100, 200, 200, 100,那么将会用线条把(0, 0), (100, 200), (200, 100)这几个位置按顺序连接起来(但首末项,也就是(200, 100)和(0,0)不会相连)。
参数 | 作用 |
arrow | 使绘制的线条加上箭头,可以是"first"(首段加上箭头), "last"(末段加上箭头), "both"(两边都加上箭头) |
arrowshape | 箭头的形状,需传递一个三项元组表示箭头的三边的长度 |
dash | 轮廓虚线 |
dashoffset | 虚线偏移 |
fill | 线段填充颜色 |
width | 线段的宽 |
smooth | 是否绘制贝塞尔曲线替代线段 |
splinesteps | 设置多少条折线构成贝塞尔曲线,需设定smooth=True,默认为12 |
stipple | 设置位图填充 |
capstyle | 设置绘制的线条首端和末端的样式,可以是"butt", "projecting", "round" |
joinstyle | 设置相邻线段相接位置的样式,可以是"round", "bevel", "miter" |
state | 设置状态 |
tags | 设置标签 |
from tkinter import *
root = Tk()
cv = Canvas(root, bg="white", highlightthickness=0)
cv.pack()
cv.create_line(10, 10, 100, 10, 10, 70, width=10)
mainloop()
capstyle和joinstyle分别设置图形端点处和连接处的样式,效果如下所示(左边端点由capstyle设置,右边连接处由joinstyle设置)。
capstyle | 效果 | joinstyle |
butt | round | |
projecting | bevel | |
round | miter |
create_oval方法用于绘制椭圆,这个方法的参数和create_arc一致。
from tkinter import *
root = Tk()
cv = Canvas(root, bg="white", highlightthickness=0)
cv.pack()
cv.create_oval(10, 10, 100, 100)
mainloop()
create_polygon用于绘制多边形,参数和create_line基本一样,但是没有capstyle参数,且多了outline等参数。需给定一系列坐标,会将它们连接起来,形成一个图形。
from tkinter import *
root = Tk()
cv = Canvas(root, bg="white", highlightthickness=0)
cv.pack()
cv.create_polygon(0, 0, 100, 100, 200, 300)
mainloop()
create_rectangle方法用于绘制矩形。参数与create_oval一致。需传递x1, y1, x2, y2表示位置。
from tkinter import *
root = Tk()
cv = Canvas(root, bg="white", highlightthickness=0)
cv.pack()
cv.create_rectangle(0, 0, 100, 100)
mainloop()
create_text方法用于绘制文本。需提供绘制的位置x, y。
参数 | 作用 |
text | 绘制的文本内容 |
font | 文本的字体 |
fill | 文本的颜色 |
anchor | 文本的锚点(x, y设置的位置),可以是八个方位或"center",”默认是"center" |
justify | 多行文本的对齐方式,可以是"left", "center", "right" |
width | 文本自动换行的宽度 |
stipple | 指定位图进行填充 |
state | 设置状态 |
tags | 设置标签 |
from tkinter import *
root = Tk()
cv = Canvas(root, bg="white", highlightthickness=0)
cv.pack()
cv.create_text(0, 0, text="Hello Canvas", font=("Arial", 14), anchor="nw")
mainloop()
create_window方法用于绘制组件,需提供绘制的位置x, y。
参数 | 作用 |
window | 组件对象 |
width | 组件的宽度 |
height | 组件的高度 |
anchor | 锚点 |
state | 设置状态 |
tags | 设置标签 |
from tkinter import *
root = Tk()
cv = Canvas(root, bg="white", highlightthickness=0)
cv.pack()
b = Button(cv, text="BUTTON")
cv.create_window(0, 0, window=b, anchor="nw")
mainloop()
画布对象有一系列的表示方式,可以是id或tag,它们可以传递到canvas的方法中。
当绘制一个画布对象,如create_text时,会返回一个值,就是画布对象的id。通过addtag可以添加tag,tag也可以用来表示一个画布对象。
有两个预定义的tag,分别是"all"和"current"。all表示所有的画布对象,current表示鼠标下的画布对象。如:删除画布的全部内容可写作:cv.delete("all")
postscript方法可以将画布内容保存下来,输出为*.ps图片文件。可设的关键字参数有:
参数 | 作用 |
colormode | 设置输出图片的颜色类型,可以是"color"(彩色), "gray"(灰度), "mono"(黑白) |
file | 设置一个文件,将输出写入到此文件中;如果不指定此参数,将会返回输出结果的字符串 |
x | 开始打印画布内容的左侧位置 |
y | 开始打印画布内容的顶端位置 |
width | 需打印画布内容的宽 |
height | 需打印画布内容的高 |
rotate | 如果设置为True,画面横向显示,否则纵向显示 |
下面是一个简单的小游戏,用户通过按键操纵球拍,接住掉落的球。球的移动需要使用Canvas来完成。为了方便理解代码,完整代码中添加了详细注释。
from tkinter import *
import random
class Ball: #定义球类
def __init__(self, racket):
self.racket = racket
self.id = cv.create_oval(0, 0, 20, 20, fill="yellow") #绘制一个黄色的圆形作为球
cv.move(self.id, WIDTH//2, HEIGHT//2) #使球初始位于窗口中央
self.xspeed = random.choice([3, -3]) #设置球的x速度
self.yspeed = -3 #设置球的y速度
def run(self):
cv.move(self.id, self.xspeed, self.yspeed) #将球移动self.xspeed, self.yspeed个像素
pos = cv.coords(self.id) #获取球的位置,返回(x1, y1, x2, y2)
if pos[0] <= 0: #如果球的位置越过屏幕左侧
self.xspeed = 3 #根据坐标系,速度设置为正则向右移动
elif pos[2] >= WIDTH: #如果球的位置越过屏幕右侧
self.xspeed = -3 #向右移动
if pos[1] <= 0: #如果球的位置越过屏幕上方
self.yspeed = 3 #向下移动
elif pos[3] >= HEIGHT: #如果球的位置越过屏幕下方
print("你失败了!")
root.destroy() #接球失败,游戏结束
if self.id in cv.find_overlapping(*cv.coords(self.racket)): #如果球碰撞到球拍
self.yspeed = -3 #球向上弹起
class Racket: #定义球拍类
def __init__(self):
self.id = cv.create_rectangle(0, 0, 90, 15, fill="blue") #绘制一个蓝色的矩形作为球拍
cv.move(self.id, WIDTH//2, 200) #设置球拍的初始位置
self.xspeed = 0 #球拍默认不移动
root.bind("", self.move_left) #按左键执行self.move_left
root.bind("", self.move_right) #按右键执行self.move_right
def run(self):
pos = cv.coords(self.id) #获取球拍位置
if (pos[0] <= 0 and self.xspeed < 0) or \
(pos[2] >= WIDTH and self.xspeed > 0): #如果移动方式会导致球拍超出屏幕范围
self.xspeed = 0
else:
cv.move(self.id, self.xspeed, 0) #移动球拍
def move_left(self, event): #左移
self.xspeed = -3
def move_right(self, event): #右移
self.xspeed = 3
root = Tk()
root.focus_force() #使窗口获取焦点
cv = Canvas(root, bg="white", highlightthickness=0)
cv.pack()
root.update()
WIDTH = root.winfo_width()
HEIGHT = root.winfo_height() #获取窗口宽高
racket = Racket()
ball = Ball(racket.id)
def run():
racket.run()
ball.run()
root.after(20, run)
root.after(20, run) #20毫秒后执行run
root.mainloop()
上面讲述的组件,只需要导入tkinter就能使用。tkinter还提供了一些子模块,你需要导入它们来使用它们提供的一些拓展的功能。
这个模块中存储了一些常用变量,在给组件指定一些参数的时候会用到。比如设置组件的relief参数,可以设为"flat", "groove"等。constants里面就有两个变量FLAT="flat", GROOVE = "groove"。这些字符串全部大写作为变量名。因此如果导入了这个模块的全部内容,Scale(root, orient="vertical")也可写作Scale(root, orient=VERTICAL)
这样做可能是为了方便拼写检查,减少错误。有些编辑器对于不存在的变量会进行突出显示,如果拼写出错了会一目了然看出来。而使用字符串的话就不便看出错误的地方。
tkinter主模块中导入了constants模块的所有内容,这意味着你不需要导入这个模块也能在主模块中使用它们。调用了from tkinter import *即可直接使用里面的常量。
messagebox模块提供了一些函数,用于弹出消息框。
Python3和Python2的messagebox模块略有不同。Python2的导入方式为:
from Tkinter import tkMessageBox
Python3的导入方式为:
from tkinter import messagebox
下面介绍一下messagebox模块的函数。这些函数需要提供以下参数:
参数 | 作用 |
title | 消息框的标题 |
message | 消息框的提示内容 |
icon | 消息框显示的提示图标,可以是"error", "info", question", "warning" |
parent | 设置对话框的父窗口,父窗口在没有关闭对话框的情况下会一直处于阻塞禁用的状态;默认是主Tk窗口,如果启动对话框时未创建Tk,则会自动创建一个Tk |
type | 设置消息框下方的按钮,可以是"ok"(确定按钮), "okcancel"(确定、取消按钮), "retrycancel"(重试、取消按钮), "yesno"(是、否按钮), "yesnocancel"(是、否、取消按钮), "abortretryignore"(中止、重试、忽略按钮) |
default | 默认激活哪一个按钮,可以是"abort"(中止), "retry"(重试), "ignore"(忽略), "ok"(确定),"cancel"(取消), "yes"(是), "no"(否) |
下面是各函数的运行效果,以及点击按钮分别的返回值:
方法 | 效果 | 返回值 |
showinfo | "ok" | |
showwarning | "ok" | |
showerror | "ok" | |
askquestion | "yes"或"no" | |
askokcancel | True或False | |
askyesno | True或False | |
askyesnocancel | True或False或None | |
askretrycancel | True或False |
注:messagebox有一个_show函数,这几个参数都是根据_show方法进行处理的。_show方法显示一个messagebox,但是返回值是按钮的名称(按钮名称参见default参数)。上面的这些方法中的一部分对_show方法返回的按钮名称进行了处理,比如askokcancel,返回的是True或False而非"ok"或"cancel"。
弹出消息框的时候,窗口会一直阻塞等待,直到给出按钮选择。如果你不清楚这是怎么做到的,可以去参考上方组件基类的wait_variable方法讲解。
from tkinter import *
from tkinter import messagebox
root = Tk()
root.title("游戏界面")
res = messagebox.askyesno("提示", "你输了,是否继续?")
'''
也可写作messagebox.askyesno(title="提示", message="你输了,是否继续?")
但是title/message是函数中最前面的两个参数,这么写简单一些
'''
if res:
print("继续游戏")
else:
print("退出")
filedialog模块中提供了一些询问文件的对话框,比如弹出一个对话框,让你选择一个文件。
下面介绍filedialog的函数。这些函数中,如果用户没有选择任何文件,那么会返回空字符串。 这些函数都可以提供如下关键字参数。
参数 | 作用 |
defaultextension | 默认后缀名;如果用户未指定文件名后缀,则默认使用此后缀名 |
filetypes | 设置可选的文件类型;是多个元组组成的序列,每个元组需提供两个项,一个是文件的描述,一个是文件的后缀,如"*.txt",如果不限文件后缀名,可以写作"*.*";关于文件后缀名的写法比较自由,指定txt文件可以写作"*.txt",也可以写作".txt", "txt" |
initialdir | 文件选择对话框弹出时,默认位于哪一个文件夹 |
initialfile | 文件选择框弹出时,默认选中哪一个文件 |
parent | 设置对话框的父窗口,父窗口在没有关闭对话框的情况下会一直处于阻塞禁用的状态;默认是主Tk窗口,如果启动对话框时未创建Tk,则会自动创建一个Tk |
title | 对话框的标题 |
multiple | 是否允许多选,默认为False |
下面是函数的介绍:
方法 | 作用 |
askopenfilename(**options) | 返回用户选择打开的文件名称(文件必须存在才能被选择) |
askopenfilenames(**options) | 和上面一个函数类似,不同的是此函数设置了multiple=1,允许多选 |
asksaveasfilename(**options): | 返回用户选择另存为的文件名称(文件可以不存在,但用户需指定文件名) |
askopenfile(mode="r", **options): | 用户选择打开文件名称后,返回使用open函数打开的文件对象 |
askopenfiles(mode="r", **options): | 和上面一个函数类似,不同的是此函数设置了multiple=1,允许多选 |
asksaveasfile(mode="w", **options) | 用户选择另存为的文件名称后,返回使用open函数打开的文件对象 |
askdirectory(**options) | 返回用户选择的文件目录;这个函数只支持上述关键字参数里面的initialdir, parent, title,此外还支持mustexist参数,表示是否用户只能选择现已存在的文件夹 |
from tkinter import *
from tkinter.filedialog import askopenfilename
def load():
filename = askopenfilename(filetypes=[("文本文档", "*.txt")])
if filename:
root.title(filename)
text.config(state="normal") #先设置为normal,不然不能进行更改
text.delete("1.0", "end")
text.insert("1.0", open(filename, encoding="utf-8").read())
text.config(state="disabled")
root = Tk()
root.title("Text Viewer")
menu = Menu(root)
root.config(menu=menu)
menu.add_command(label="Load", command=load)
text = Text(root, state="disabled")
text.pack()
root.mainloop()
tkinter的子模块colorchooser,用于弹出一个对话框,让用户选择一种颜色。这个模块使用方式非常简单,有一个函数askcolor,执行后即可弹出一个颜色对话框。
用户选择完颜色后,askcolor返回选取的结果,是一个元组,第一项是选取颜色的RGB元组,第二项是选取颜色的十六进制形式"#......"。如果用户点击了取消,会返回一个两项都是空的元组(None, None)。
from tkinter import *
from tkinter import colorchooser
def choose_color():
color = colorchooser.askcolor()
print(color)
root = Tk()
Button(root, text="Choose Color", command=choose_color).pack()
mainloop()
这个方法还可以提供如下关键字参数:
参数 | 作用 |
initialcolor | 颜色对话框弹出时,默认显示的颜色 |
parent | 颜色对话框的父窗口 |
title | 颜色对话框的标题 |
参考资料:tkinter.ttk --- Tk 风格的控件 — Python 3.10.6 文档
ttk是tkinter的拓展组件库,提供了一些拓展的组件:Combobox,Notebook,Progressbar,Separator,Treeview,Sizegrip。还有一些组件主模块中已经包含了,它们的样子和原来不相同,显得更加美观,它们是Button, Checkbutton, Entry, Frame, Label, LabelFrame, Menubutton, PanedWindow, Radiobutton, Scale, Scrollbar和Spinbox(还继承ttk.Entry)。这些组件都继承ttk.Widget类。
ttk在python2中的导入方式为:
import Ttk
在python3的导入方式则是:
from tkinter import ttk
参考资料:http://tktable.sourceforge.net/tile/doc/converting.txt
ttk的关键字参数也有不同,设定一些样式的时候需要用ttk.Style。下面讲一下ttk组件功能的不同。
Checkbutton(style="Toolbutton")
Radiobutton(style="Toolbutton")
下面的列表中展示了tkinter主模块组件样式,和ttk中相同组件名的组件样式(均使用默认样式)。部分样式没有太大区别的组件没有包括在表格中。当鼠标移动到ttk组件上时,样式会发生变化,比较美观。ttk不是很美观的地方在于激活后,部分组件会出现一个虚线框。
组件名 |
tkinter主模块中 |
tkinter.ttk中 |
Button | ||
Checkbutton | ||
Entry | ||
Menubutton | ||
Radiobutton | ||
Scale | (ttk.LabeledScale) | |
Spinbox |
ttk.Widget增加了一些特殊的方法,用来操作组件的状态。ttk的状态表示为一个序列,里面包含了多个状态的标志,比如("disabled", "focus")。下面是ttk可以设置的状态标志。如果在不支持某个状态标志的组件上设置了此标志,那么不会有任何效果。
状态 | 解释 |
active | 光标位于组件之上,且组件可激活,将设置此状态 |
hover | 光标位于组件之上,将设置此状态 |
disabled | 组件处于禁用状态 |
focus | 组件获取焦点,将设置此状态 |
pressed | 按钮被按下,将设置此状态(限于按钮类组件) |
alternate | 选框的值未被设定时(比如未绑定Checkbutton或Radiobutton到某个Variable),将设置此状态(限于选框类组件) |
selected | 选框处于启用、选中状态,将设置此状态(限于选框类控件) |
background | 组件的父窗口是背景窗口(后台窗口),将设置此状态 |
readonly | 组件处于只读状态,禁止用户修改 |
invalid | 当组件验证的值无效,将设置此状态(限于Entry等有validate功能的组件) |
如果要表示关闭或没有某个状态,可以在状态标志的前面加上"!"符号,如"!active"表示没有active状态。
state方法用于获取当前的状态元组,如果指定参数,也可以添加设置当前的状态。
ttk.Widget.state(statespec=None)
如下示例:
from tkinter import *
from tkinter.ttk import *
root = Tk()
b = Button(root, text="点击")
b.pack()
b.state(["disabled"]) #禁用按钮
mainloop()
需要注意的是:状态中没有normal,如果想要设定成普通的状态,需要通过!符号来关闭。把上面示例的按钮恢复正常可执行b.state(["!disabled"])。state方法用于添加状态,而不是设置!比如,设置状态为"disabled"后再执行b.state(["active"])并不代表当前组件状态变为了["active"],而是["disabled", "active"]。
instate方法则用于检查组件的状态。
ttk.Widget.instate(statespec, callback=None, *args, **kw)
当组件状态符合statespec所指定状态时返回True,否则返回False。如果指定callback,那么符合状态时将会调用这个函数,并将*args, **kw传递给该回调函数。
参考资料:tkinter.ttk --- Tk 风格的控件 — Python 3.10.6 文档 -- ttk.Style
ttk.Style可以用于设定组件的样式。在部分组件中,你无法直接设置组件的背景前景色、字体,但可以通过定义Style来达到这个功能。当然,ttk.Style还有更强大的地方。
一般来说一个程序里,只需调用一次ttk.Style即可。可以通过设置ttk组件的style参数,使组件应用指定的Style。
下面是Style类的常用方法,接下来会详细介绍其中的一部分。
方法 | 作用 |
configure(style, query_opt=None, **kw) | 获取或设置某个样式的基本选项 |
map(style, query_opt=None, **kw) | 获取或设置某个样式的动态选项 |
lookup(style, option, state=None, default=None) | 返回某个样式的option选项值,state是组件的状态序列,用来筛选,default是值缺失时设置的默认值 |
layout(style, layoutspec=None) | 获取或设置style的控件布局属性 |
element_create(elementname, etype, *args, **kw) | 在当前主题下创建一个元素 |
element_names() |
返回当前主题的元素列表 |
element_options(elementname) | 返回指定元素的属性列表 |
theme_create(theme_name, parent=None, settings=None) | 创建一个主题 |
theme_settings(themename, settings) | 将主题临时设为themename并应用settings,然后恢复原来的主题 |
theme_names() | 返回当前主题的列表(包括内置主题) |
theme_use(themename=None) | 获取或设置当前主题 |
from tkinter import *
from tkinter import ttk
root = Tk()
style = ttk.Style()
style.configure("TButton", foreground="red", font="黑体")
b = ttk.Button(root, text="按钮")
b.pack()
root.mainloop()
创建了一个Style对象后,如上段代码所示,执行了Style.configure方法。这个方法的作用是设置或更改某个组件类的样式。
Style.configure(style, query_opt=None, **kw)
style是样式更改的类名,**kw是设置的参数选项。调用后所有应用style的组件都会变成**kw的指定的参数选项样式。其中**kw参数只能是组件支持的关键字参数,比如background, foreground, relief, font, padding等。如果参数选项是该组件不支持的,不会报错,但是什么效果也没有。
对ttk的组件执行winfo_class()方法,可以获取该组件的类名。ttk的组件的类名十分特殊,ttk.Button的类名不是Button,而是TButton。一般来说,ttk组件的类名是组件名称的title形式(只有首字母大写,比如是TPanedwindow而不是TPanedWindow)前面加上大写T。对于一些支持orient参数的组件,类名还可以是Horizontal.TScale或Vertical.TScale,设置水平状态的style或垂直状态的style。有一个特殊一点的组件Treeview(ttk新增组件,后面介绍),它的类名不是TTreeview,而是不变的,写作Treeview。
类名还可以进行分类。以按钮为例,如果想要做一个红色和一个蓝色前景的按钮,就需要对类名进行分类,不然都是一个样式的。分类的方式是:在类名前面加上Style的分类名称,用句点隔开。定义组件时,用style参数指定该组件使用的分类样式。
from tkinter import *
from tkinter import ttk
root = Tk()
style = ttk.Style()
style.configure("r.TButton", foreground="red", font="黑体")
style.configure("b.TButton", foreground="blue", font="黑体")
b = ttk.Button(root, text="按钮", style="r.TButton")
b.pack()
b = ttk.Button(root, text="按钮", style="b.TButton")
b.pack()
root.mainloop()
configure方法也可以用于查询某个**kw选项的值。需指定query_opt选项。如:查询TButton风格的foreground参数,并赋值给fg,可写作fg = style.configure("TButton", "foreground")
map方法和configure类似,都是用来获取或设置某个style的样式。但不同的是,map设置的参数是“动态”的,你可以指定设定该style的组件处于某种state的时候参数的值。
Style.map(style, query_opt=None, **kw)
query_opt用来查询,和configure用法一样。下面举一个例子演示一下**kw指定参数和configure的不同。
from tkinter import *
from tkinter import ttk
root = Tk()
style = ttk.Style()
style.configure("TButton", foreground="black")
style.map("TButton", foreground=[("focus", "red"), ("hover", "blue")])
b = ttk.Button(root, text="按钮", style="TButton")
b.pack()
mainloop()
代码段中关于map的这一行是这个意思:如果组件处于"focus"(焦点)状态,那么foreground设为"red",如果组件处于"hover"(鼠标位于上方)状态,那么foreground设为"blue"。如果组件状态为空列表,那么则使用默认的foreground="black"。
这个状态的条件可以指定多个,比如,下面的代码表示,当组件处于"pressed"状态但不处于"focus"状态(!表示否定)的时候改变前景色为"red"。
style.map("TButton", foreground=[("pressed", "!focus", "red")])
注:上面的这行代码中,如果组件设置了takefocus=True,那么"pressed"同时"!focus"的状态是不可能实现的。 但如果设置了takefocus=False,使组件禁止获取焦点,那么鼠标按在按钮上时就可以达到变前景色为"red"的效果。
ttk的组件可以被划分为多个部分,每个部分称为元素。比如ttk.Menubutton是这个样子的:
通过查询Menubutton的layout(下一节介绍),Menubutton可以被划分为几个元素:label, button, padding, dropbutton。其中label, button, padding是每个组件都可以使用的公用元素。dropbutton是下拉箭头,是Menubutton的专属元素。当我们表示元素的时候,可以用"Menubutton.dropbutton", "Vertical.Scrollbar.uparrow"(指的是Scrollbar组件的上箭头), "这样的写法(注意:此处不是TMenubutton或TScrollbar!)
注:“公用元素”“专属元素”并不属于官方规定的术语,关于元素的知识在ttk文档中没有过多记述,因此找不到一个标准的叫法。
公用元素在任何组件都可以以组件名称来命名,如"Button.label", "Button.button", "Label.label",而专属的元素需要指定父组件,如"Menubutton.dropbutton"而不是"Button.dropbutton"。
下面介绍一下公用的元素。
元素名称 | 解释 |
label | 表示一个标签,显示文本或图像 |
button | 表示可以点击的按钮 |
focus | 表示组件获取焦点后显示的虚线框,不影响组件焦点设置 |
padding | 表示一个支持内部间隔的框架,此类组件支持-padding参数,表示内部留白 |
element_create方法用于创建一个自定义元素。
element_create(elementname, etype, *args, **kw)
elementname设置自定义元素的名称,etype是类型,可以是"image"或"from"。
如果etype="image",那么*args需传递 图片对象 和 一系列状态与图片对象组成的元组 ,kw可提供border(图片左、上、右、下的边界), padding(图片内部的留白), sticky(图片对齐方式), width(图片最小宽度), height(图片最小高度)。
如果etype="from",那么*args需传递主题名称(下面介绍)和元素名称(如果不提供将会使用空元素),这会复制给定的元素,此时无需传递kw。
在下一节中,会对这些知识进行应用。
layout方法用于获取或设置组件的形态。因为ttk的组件都是由元素构成的,所以我们可以对这些元素进行修改,来设计全新样式的组件。
from tkinter import *
from tkinter.ttk import *
from pprint import pprint #漂亮打印
root = Tk()
style = Style()
pprint(style.layout("TButton"))
通过下面的代码,我们可以获取在"TButton"样式中Button组件的layout样式。 因为打印出的是一个非常复杂的,嵌套了很多列表元组字典的一个列表,所以我使用pprint对打印出的内容进行美化。
下面就来解释一下含义。首先layout的表示方式,是一个列表,可以把这个列表理解为一个Frame。在这个列表中,可以有多个元组,这个元组可以理解为一个元素组件。在这个元组中,第一项是元素的名称,第二项是一个字典代表这个元素的布局属性(也可以是None)。这些属性可以是:side, sticky, children(是一个列表,将元素自身作为一个容器用来排放子元素), unit(0或1,如果设为1,那么这个元素将可以被Widget.identify方法使用。这个方法需传递相对于控件内部的x, y位置,返回位于这个坐标的元素控件名)。
下面是一个示例,演示了如何自定义一个Button。
from tkinter import *
from tkinter.ttk import *
root = Tk()
style = Style()
style.layout("mystyle.TButton", [("Button.button", {"sticky":"nswe"}),
("Button.label", {"sticky":"nswe"})])
Button(root, text="MyTButton", style="mystyle.TButton").pack()
mainloop()
因为没有指定side,而是指定了sticky设置四个方向填充,所以按钮和文字组件在同一个地方。
上一节介绍了element_create方法,下面就用这个方法制作一个元素。在处于hover状态,处于focus状态时,样式都会有变化。
from tkinter import *
from tkinter.ttk import *
root = Tk()
img_normal = PhotoImage(file="这是一个按钮.png")
img_hover = PhotoImage(file="鼠标在按钮上.png")
img_focus = PhotoImage(file="按钮获取焦点.png")
style = Style()
style.element_create("ImgEle", "image", img_normal,
[["hover"], img_hover],
[["focus"], img_focus])
style.layout("mystyle.TButton", [("ImgEle", {"sticky":"nsew"})])
Button(root, text="MyTButton", style="mystyle.TButton").pack()
mainloop()
这样,当按钮正常状态时会显示:这是一个按钮.png;鼠标移动到按钮上时会显示:鼠标在按钮上.png;点击按钮使其获取焦点会显示:按钮获取焦点.png。
参考资料:TkDocs Tutorial - Styles and Themes
如果将多个对组件样子的设置集中到一起,就形成了主题。计算机系统有一些内置主题,它们是"alt", "default", "clam", "classic"。Mac系统还有一个额外的主题"aqua",Windows则还有"vista", "winxpnative"(或"xpnative")和"winnative"。
theme_use方法用来设置或获取当前主题,主题设置时,会刷新所有的组件,并发送一个虚拟事件<
theme_create方法用于自己建立主题。
theme_create(theme_name, parent=None, settings=None)
theme_name是自定义主题的名称,如已经存在将会报错。如果指定parent,那么这个主题的样式会继承父主题,主题设置不更改的地方参照父主题。settings是主题的设置,需传递一个字典,键为组件名称,如TButton,值为此组件的设置。组件的设置也是一个字典,可以包括四个键"configure", "map", "layout"和"element create",所对应的值分别和Style这几个方法期望的格式相同。但是"element create"只能传递一个元素的(etype, *args),不能设置元素名。元素名字默认被设为该组件的名称(如:TButton)。
下面的示例对Button的样式进行了修改。
from tkinter import *
from tkinter.ttk import *
root = Tk()
img_normal = PhotoImage(file="这是一个按钮.png")
img_hover = PhotoImage(file="鼠标在按钮上.png")
img_focus = PhotoImage(file="按钮获取焦点.png")
layout = [("TButton", {"sticky":"nsew"})]
element_create = ("image", img_normal,
[["hover"], img_hover],
[["focus"], img_focus])
style = Style()
style.theme_create("MyTheme", settings=
{"TButton":{
"element create":element_create,
"layout":layout
}
}
)
style.theme_use("MyTheme")
Label(root, text="Theme: '%s'"%style.theme_use()).pack()
Button(root, text="Button").pack()
mainloop()
Combobox是文本框和下拉列表框的综合,用户既可以从下拉列表中选取数据,也可以输入文本。Combobox类继承ttk.Entry。
Combobox(master=None, **kw)
ttk的组件参数可能与主模块中有不同的地方,所以公用参数也会进行介绍。
参数 | 作用 |
exportselection | 这个是所有含有输入功能的组件的共有参数,表示选中的内容是否可以被Misc.selection_get方法检测到,参见对Misc类的介绍 |
justify | 文本在组件内的对齐方式,可以是"left", "center", "right",默认为"left" |
width | 组件的宽,单位为字符单位 |
height | 组件的高 |
state | 组件的状态,可以是"normal", "disabled", "readonly";"readonly"状态下,只能从下拉列表选取选项,不能输入编辑 |
values | 设置显示在下拉列表中的值(一个序列的形式) |
textvariable | 与组件的值相关联的Variable |
postcommand | 当下拉列表弹出时调用的回调函数 |
常用方法:
方法 | 作用 |
current(newindex=None) | 将组件的值设为values[newindex],如果不指定newindex,返回当前值在values中的位置,如果不在返回-1 |
get() | 返回组件的值 |
set(value) | 设置组件的值 |
from tkinter import *
from tkinter import ttk
root = Tk()
box = ttk.Combobox(root, values=("中文-English", "English-中文"))
box.pack()
mainloop()
当下拉列表中的内容被选取时,会向Combobox发送一个虚拟事件<
from tkinter import *
from tkinter import ttk
root = Tk()
box = ttk.Combobox(root, values=("中文-English", "English-中文"))
box.pack()
box.bind("<>", lambda e: print("选取了", box.get()))
mainloop()
Separator组件显示一个分割线的图案,用于美化界面。
Separator(master=None, **kw)
参数 | 作用 |
orient | 设置分割线的朝向,可以是"horizontal", "vertical",默认是水平 |
from tkinter import *
from tkinter.ttk import *
def this(): #返回Python之禅的文本
from this import s
d = {}
for c in (65, 97):
for i in range(26):
d[chr(i+c)] = chr((i+13) % 26 + c)
return "".join([d.get(c, c) for c in s])
root = Tk()
Label(root, text="The Zen of Python", font=("Arial", 20, "bold")).pack()
Separator(root).pack(fill="x", pady=5) #添加分割线
Label(root, text=this()).pack(padx=5)
mainloop()
可以发现,分割线很好地起到了分隔、美化界面的作用。
Sizegrip组件在屏幕上添加一个拖动柄,用于调节窗口的大小。
Sizegrip(master=None, **kw)
此组件除了来自ttk.Widget的方法外,没有别的参数或方法。
from tkinter import *
from tkinter.ttk import *
root = Tk()
sg = Sizegrip(root)
sg.pack(side="bottom", anchor="e", padx=20, pady=20) #靠左下角排放
mainloop()
ttk.Notebook管理一个Frame的集合,允许添加多个选项卡,让用户在选项卡之间来回进行切换。
Notebook(master=None, **kw)
参数 | 作用 |
width | 设置宽 |
height | 设置高 |
padding | 设置内部留白 |
常用方法:
方法 | 作用 |
add(child, **kw) | 添加一个新的选项卡 |
forget(tab_id) | 删除tab_id指定的选项卡 |
hide(tab_id) | 隐藏tab_id指定的选项卡 |
identify(x, y) | 返回位于x, y的组件名 |
index(tab_id) | 返回tab_id指定的索引 |
insert(pos, child, **kw) | 在pos索引处插入选项卡 |
select(tab_id) | 选中tab_id指定的选项卡 |
tab(tab_id, option=None, **kw) | 如果指定option,则查询tab_id选项卡的参数;如果指定**kw,则设置选项卡的参数值 |
tabs() | 返回选项卡的Frame列表 |
enable_traversal() | 启用Notebook的快捷键,调用后会为组件添加绑定事件: |
from tkinter import *
from tkinter.ttk import *
root = Tk()
note = Notebook(root)
note.pack()
mainloop()
这段代码创建一个空的Notebook,里面什么内容也没有。
from tkinter import *
from tkinter.ttk import *
root = Tk()
note = Notebook(root)
note.pack()
f1 = Frame(note)
f2 = Frame(note)
f3 = Frame(note)
Button(f1, text="按钮").pack()
Label(f2, text="标签").pack()
note.add(f1, text="TAB 1")
note.add(f2, text="TAB 2")
note.add(f3, text="TAB 3")
mainloop()
add方法用于在Notebook中添加选项卡,让用户在选项卡之间自由切换。
add方法需先传递一个父容器为此Notebook的Frame,然后需要设定这个选项卡的参数。可以设定的参数如下。
参数 | 作用 |
state | 选项卡的状态,可以是"normal", "disabled"(禁用,无法选中), "hidden"(隐藏) |
sticky | 设置选项卡Frame在Notebook面板内的布局位置 |
padding | 设置组件排放Frame的留白空间 |
text | 设置显示的文本 |
image | 设置显示的图片 |
compound | 图片位于文本的方位 |
underline | 设置文本下划线的位置,如果执行了enable_traversal方法,下划线的文本可以用于Alt快捷键绑定 |
表示一个Notebook的选项卡,可以有以下方式。
当选项卡的选中变化时,会生成虚拟事件<
Progressbar用于添加进度条控件,可以设置此进度条的值。
Progressbar(master=None, **kw)
参数 | 作用 |
orient | 设置组件的朝向 |
length | 设置进度条的长度 |
mode | 设置进度条的模式,可以是"determinate"(默认), "indeterminate" |
maximum | 设置进度条的最大值 |
value | 进度条当前的值 |
variable | 与进度条当前值相关联的Variable |
常用方法:
方法 | 作用 |
step(amount=None) | 将进度条的值增加amount;如不指定amount,默认增加1 |
start(interval=None) | 进度条开始自动增加,每隔interval毫秒增加1;如不指定interval,默认为50毫秒 |
stop() | 停止自动增加 |
from tkinter import *
from tkinter.ttk import *
root = Tk()
bar = Progressbar(root, length=200, maximum=100, value=30)
bar.pack(padx=10, pady=10)
mainloop()
上面的代码创建了一个位于30/100位置的进度条。
start和stop方法分别用于开始和结束进度条的自动增加。当进度条加载完时,会回到开头继续加载。
mode参数用于设定进度条的模式。determinate模式下,进度条会不断增加。而indeterminate模式下,进度条会显示成一个小方块,在进度条的槽中来回运动。默认的模式是determinate,效果如下。
indeterminate模式效果如下。
一般,我们在知道进度条要加载的进度时会选用默认的模式,而不知道进度的时候会选用第二种模式。
Treeview用于添加树状图控件,这个树状图是一个表格的形式,且有层级之分。
Treeview(master=None, **kw)
参数 | 作用 |
columns | 是一个序列,指定表格中显示的列,序列汇总每个项代表此列的标识名称 |
height | 设置表格的高 |
padding | 设置内部留白 |
selectmode | 设置可以选中的模式,可以是"extended"(多选,默认), "browse"(单选), "none"(无法选择) |
show | 设置要显示表格哪些部分,可以是"tree"(在#0的位置显示文本标签), "headings"(显示标题行), 也可以是两个组成的列表或空列表。默认是("tree", "headings")表示全部显示 |
常用方法:
方法 | 作用 |
bbox(item, column=None) | 返回item数据项相对于Treeview的边界,形式为(x, y, width, height),如指定column,则返回此单元格边界 |
get_children(item=None) | 返回item的子数据项列表,如果不指定item则返回最顶级的数据项列表 |
set_children(item, *newchildren) | 用newchildren替换item的子数据项 |
column(column, option=None, **kw) | 查询或修改某一列的参数选项 |
delete(*items) | 删除item数据项以及子数据项 |
detach(*items) | 将items数据项隐藏 |
exists(item) | 判断item数据项是否在Treeview中 |
focus(item=None) | 将item数据项设为当前焦点,如不指定item则返回当前焦点数据项,如无焦点则返回空字符串 |
heading(column, option=None, **kw) | 查询或修改column数据列的参数选项 |
identify(component, x, y) | 返回x, y位置上component数据项的描述信息,如无则返回空字符串 |
identify_row(y) | 返回y位置上的数据项 |
identify_column(x) | 返回x位置上的数据列 |
identify_region(x, y) | 返回x, y位置上的类型,返回值有:"heading"(标题栏), "separator"(标题之间的分割线), "tree"(树的区域), "cell"(单元格)(Tk 8.6可用) |
identify_element(x, y) | 返回位于x, y的数据项(Tk 8.6可用) |
index(item) | 返回item位于其父项的子项列表中的索引 |
insert(parent, index, iid=None, **kw) | 插入数据项 |
item(item, option=None, **kw) | 查询或修改item数据项的参数选项 |
move(item, parent, index) | 将item数据项移动到parent父项的index位置 |
next(item) | 返回item项的下一项,如果此项为其父项的最后一个子项,则返回空字符串 |
parent(item) | 返回item项的父项,如果为最顶级数据项则返回空字符串 |
prev(item) | 返回item项的上一项,如果此项为其父项的第一个子项,则返回空字符串 |
see(item) | 滚动Treeview使item数据项可见 |
selection(item) | 返回所有选中项 |
selection_set(*items) | 使items成为新的选中项 |
selection_add(*items) | 将items加入选中项 |
selection_remove(*items) | 从选中项中移除items |
selection_toggle(*items) | 切换items各项的选中状态 |
set(item, column=None, value=None) | 如指定item,则返回item的{列:单元格值, ...}字典;如指定两个参数,返回此单元格的值;如指定三个参数,则设置此单元格的值 |
tag_bind(tagname, sequence=None, callback=None) | 对tag进行事件绑定 |
tag_configure(tagname, option=None, **kw) | 对含有指定tag的数据项的参数选项进行查询或设置,**kw参数可以设置foreground, background, font, image(当数据项图片为空时) |
tag_has(tagname, item=None) | 如指定item,根据item是否有指定tag返回1或0;如不指定,则返回设置了指定tag的所有数据项 |
Treeview继承XView和YView,所以还支持两个方向的滚动条方法。
from tkinter import *
from tkinter.ttk import *
root = Tk()
tree = Treeview(root, columns=("A", "B", "C"))
tree.pack()
mainloop()
这段代码创建了一个Treeview,有三个列,名字分别为"A", "B", "C"。 实际运行时,除了这三列,在所有列的前面还多了一列,是Treeview的文本标签列。隐藏文本标签列,可以设定show参数。
如果要访问列,可以使用索引或者列的名字。文本标签列的索引是"#0",后面的列依次为"#1", "#2", "#3"……即使隐藏了文本标签列,后面的列的索引依然不会变化。因为在指定Treeview时columns参数设置了列的名字,所以后面的列也可以用"A", "B", "C"来表示。
heading方法用于查询或修改标题栏。首先需提供这一列的索引或名字,然后指定需要获取或设置的参数。可以指定的参数有:
参数 | 作用 |
text | 列的标题的文本 |
image | 列标题的图片(显示于文本右侧) |
anchor | 对齐方式锚点 |
command | 点击标题执行的回调函数 |
from tkinter import *
from tkinter.ttk import *
root = Tk()
tree = Treeview(root, columns=("A", "B", "C"))
tree.pack()
tree.heading("#0", text="文本标签")
tree.heading("#1", text="A列") # "#1"也可换成"A"
tree.heading("#2", text="B列")
tree.heading("#3", text="C列")
mainloop()
insert方法用来插入项目,一个数据项代表一行。
Treeview.insert(parent, index, iid=None, **kw)
parent指定项目的父项,由于Treeview是可以分层的,所以可能有项目层级的嵌套;如果是顶层的项目,可以将parent设为空字符串。index指定插入的位置,可以是一个整数索引或者"end"。iid指定此项目的标识符,如果想要对项目进行访问,需要提供项目的iid;iid不能和之前定义过的iid相重复;可以从方法列表中看到,很多方法都需要提供item参数,item代表的正是项目的iid。**kw参数如下:
参数 | 作用 |
text | 文本标签栏处显示的文本 |
image | 文本标签栏显示的图片(在文本左侧) |
values | 指定每列单元格的值,是一个序列,应与columns参数指定的列数相同 |
open | 是否显示此数据项的子项 |
tags | 与该数据项关联的tag列表 |
insert方法执行后返回添加的数据项的iid。
from tkinter import *
from tkinter.ttk import *
root = Tk()
tree = Treeview(root, columns=("A", "B", "C"))
tree.pack()
tree.heading("#1", text="A")
tree.heading("#2", text="B")
tree.heading("#3", text="C")
tree.insert("", "end", text="1", values=("A1", "B1", "C1"))
tree.insert("", "end", text="2", values=("A2", "B2", "C2"))
mainloop()
如下是分层级的Treeview示例:
from tkinter import *
from tkinter.ttk import *
root = Tk()
tree = Treeview(root, columns=("A", "B", "C"))
tree.pack()
tree.heading("#1", text="A")
tree.heading("#2", text="B")
tree.heading("#3", text="C")
tree.insert("", "end", iid="1", text="1", values=("A1", "B1", "C1")) #设置iid="1"
tree.insert("1", "end", text="2", values=("A2", "B2", "C2")) #设置父项为iid="1"的项目
mainloop()
运行后出现一个加号,点击加号可以打开子项。
Treeview组件会引发如下虚拟事件:
事件 | 条件 |
< |
Treeview的选中项目改变 |
< |
当焦点所在项的子项展开(open=True) |
< |
当焦点所在项的子项合并(open=False) |
tkinter.font模块中提供了一些关于字体的操作。首先要介绍的是font.Font类,这个类指定一个类型的字体,这个类的字符串形式可以被直接传递给组件的-font参数。
可以提供以下关键字参数:
参数 | 作用 |
font | 指定字体样式,可以是一个字体名或者字体元组,如("宋体", 12) |
name | 此类字体的名称,指定后可以传递给组件font="MyFontName" |
exists | 字体是否已经存在于系统,如果设置为True而字体并不存在,则报错 |
还可以提供下面的关键字参数,这组参数和上面的参数font, exists(name除外)不用重复指定:
参数 | 作用 |
family | 字体名称,如"宋体", "黑体", "Arial", "Times" |
size | 字体尺寸大小 |
weight | 字体的厚度,可以是"normal"(普通), "bold"(加粗) |
slant | 字体的倾斜样式,可以是"roman"(无倾斜), "italic"(倾斜) |
underline | 是否有下划线 |
overstrike | 是否有删除线 |
示例如下:
from tkinter import *
from tkinter import font
root = Tk()
f = font.Font(family="黑体",
size=16,
slant="italic",
underline=True)
Label(root, text="Tip:这是一段文字", font=f).pack()
mainloop()
Font类还支持如下方法:
方法 | 作用 |
copy() | 将当前字体复制,返回一个Font对象 |
actual(option=None, displayof=None) | 返回字体的属性信息,如不指定option,返回值如:{'family': '黑体', 'size': 16, 'weight': 'normal', 'slant': 'italic', 'underline': 1, 'overstrike': 0} |
cget(option) | 返回字体的option属性信息,相当于font.actual(option=option) |
config(**option) |
更改字体的选项 |
measure(text, displayof=None) | 返回text字符串使用此字体时的文本宽度(像素) |
metrics(*options, **kw) | 返回字体的度量信息,如不指定options,返回值如:{'ascent': 18, 'descent': 3, 'linespace': 21, 'fixed': 1} |
除了Font类,font模块还提供了两个方法。
方法 | 作用 |
families(root=None, displayof=None) | 返回系统上所有的可用字体名称 |
names(root=None) | 返回自定义的字体名称 |
当调用names()方法的时候,我们会发现tk有一些预定义的字体,也可以使用它们:
('fixed', 'oemfixed', 'TkDefaultFont', 'TkMenuFont', 'ansifixed', 'systemfixed', 'TkHeadingFont', 'device', 'TkTooltipFont', 'defaultgui', 'TkTextFont', 'ansi', 'TkCaptionFont', 'system', 'TkSmallCaptionFont', 'TkFixedFont', 'TkIconFont')
scrolledtext模块中提供了一个ScrolledText类,继承自Text。和Text不同的是,这个组件在外观上多了一个y方向的滚动条。其他使用方法与Text一致。如果想要制作带有滚动条的Text,使用这个组件可以方便许多。
以上介绍的这些子模块都是最为常用的。除了这些以外,tkinter还有以下子模块。
子模块 | 描述 |
commondialog | 提供了调用tk对话框的基类;功能已被messagebox, filedialog等替代 |
dialog | 提供了一个对话框,可设置标题,提示语,按钮等;样式较为简陋 |
dnd | 用于实现组件拖拽移动功能;该模块是实验性的,后期会被替代 |
simpledialog | 提供了一些询问字符串、整数等类型的对话框;样式较为简陋,而且是英文版的 |
tix | 提供了一些拓展组件;如今比较过时,可用ttk替代 |
Python官网(tkinter模块):tkinter —— Tcl/Tk 的 Python 接口 — Python 3.10.5 文档https://docs.python.org/zh-cn/3/library/tkinter.html#module-tkinterhttps://docs.python.org/zh-cn/3/library/tkinter.html#module-tkinter
Python tkinter源代码的github:cpython/Lib/tkinter at 3.10 · python/cpython · GitHubThe Python programming language. Contribute to python/cpython development by creating an account on GitHub.https://github.com/python/cpython/tree/3.10/Lib/tkinterhttps://github.com/python/cpython/tree/3.10/Lib/tkinter
Tcl/Tk主页:Tcl Developer Sitehttps://www.tcl.tk/https://www.tcl.tk/
Tk教程文档主页:TkDocs HomeTkDocs features tutorials and other material for modern Tk GUI development, using Python/Tkinter, Tcl, Ruby, and Perl/Tkx.http://tkdocs.com/http://tkdocs.com/
Tcl是一种解释型脚本语言,并不包含窗口GUI的操作。Tk是Tcl的GUI图形扩展,以Tcl语言为基础,提供了大量的组件和窗口操作。如果Tcl/Tk没有Tk,那么就只有空的语法,只有赋值、判断、循环这些基础操作,无法创建窗口。
如果要创建一个Tcl/Tk解释器,只需要用Tk类就可以。Tk创建一个顶层窗口,也会创建一个新的Tcl/Tk解释器。它和Toplevel的不同点就在于Tk会创建新的解释器,而Toplevel不会。
如果不需要使用Tk,只使用Tcl的语法,那么可以在Tk类的参数设置useTk=0,也可以使用Tcl函数。Tcl函数返回一个useTk=0的Tk对象。如下:
tcl = Tk(useTk=0)
tcl = Tcl()
#不使用tk
如果设置了useTk=0,那么不能使用与Tk相关的任何方法。
Tk类里面有一个实例变量tk,是_tkinter.tkapp对象(tkinter前面加一个下划线,是tkinter的内建模块,是用Tcl/Tk编写,里面定义了TclError, Tcl_Obj, TkappType几个对象),它有一些方法,能够调用Tcl/Tk的命令。这些方法,也可以直接作为Tk或其他组件对象的方法调用。
方法 | 作用 |
call(...) | 在Tcl解释器中执行Tcl/Tk命令,需提供一系列在Tcl语言中用空格隔开的命令作为参数,如果是命令用字符串代替,如:一段Tcl命令set num 2可写成tk.call("set", "num", 2) |
createcommand(name, func) | 在Tcl解释器中建立一个name过程(Tcl语言中没有函数,但是有命令或过程的概念,相当于Python中的函数),具有func函数的作用 |
deletecommand(name) | 在Tcl解释器中删除name过程 |
eval(script) | 在Tcl解释器中执行script命令(script是一个字符串) |
evalfile(fileName) | 在Tcl解释器中运行tcl程序文件(*.tcl) |
getvar(name) | 返回Tcl解释器中名为name变量的值 |
setvar(name, value) | 在Tcl解释器中定义一个名为name的变量,值为value |
unsetvar(name) | 在Tcl解释器中删除名为name的变量 |
mainloop() | 进入主循环 |
示例如下:
from tkinter import *
root = Tk()
button = Button(root, name="busyButton", text="BUSY...")
button.pack()
root.call("tk", "busy", "hold", ".busyButton")
Button(root, text="cancel", command=lambda: root.call("tk", "busy", "forget", ".busyButton")).pack()
root.mainloop()
这个示例使用了tk的busy使组件处于无法接收事件的忙碌状态,可详见
Python tkinter一些十分灵活的运用方式和实用函数的第8节。
由于篇幅有限,将此节内容附到下面的文章中。一共整理了760种Tk支持的颜色。
Tk 颜色样式、颜色名称、RGB值、十六进制值列表_Python zzy的博客-CSDN博客
如果你在开发Python tkinter程序时遇到了问题,或是有文章内容的建议,可以私信联系我,感谢支持!