上一篇:Python tkinter(GUI编程)模块全解(中)_Python zzy的博客-CSDN博客

总目录:tkinter/README.md · Python-ZZY/CSDN-articles - Gitee.com

2 tkinter主模块

2.24 Canvas

Canvas是画布组件,用户可以在上面绘制图形、图像、文本、组件,还可以使上面的绘制对象移动。

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

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

参数作用
highlightthickness设置高亮边框的宽度;这个参数大部分组件都有,这里提出来需要强调的是,Canvas是有highlightthickness的,这使得有时边框会变色,影响效果,所以每次建立Canvas的时候最好设为0
scrollregion设置Canvas的滚动范围,格式是(x1, y1, x2, y2),代表左上角坐标和右下角坐标构成的一个矩形,如果不指定无法正常使用滚动条
confine是否允许滚动超过scrollregion指定的范围,默认为True
xscrollcommandx方向滚动
yscrollcommandy方向滚动
xscrollincrementx方向滚动步长,如"2c"表示2厘米,可选单位有"c"(厘米), "i"(英寸), "m"(毫米), "p"(DPI)
yscrollincrementy方向滚动步长,格式同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方法

create_arc方法用来绘制扇形,弓形或弧形。首先需传递四个参数代表(x1, y1, x2, y2)。下面是**kw选项。

参数作用
dash指定绘制虚线轮廓,是偶数个项目的元组,代表虚线每段长度和间隔;如(2, 5)表示虚线每段长度为2,每段间隔为5;如(2, 5, 4, 5)表示虚线为每段长度为2,每段间隔为5,每段长度为4,每段间隔为5的循环绘制
dashoffset设置虚线开始绘制的偏移
extent形状的角度(默认为90)
fill填充的颜色,默认为空字符串表示无填充
stipple使用位图作为填充,默认为空字符串表示无填充
outline轮廓的颜色
outlinestipple设置一种位图填充轮廓,需设定outline
start起始位置的偏移
width轮廓的宽度
style绘制的样式,可以是"pieslice"(扇形,默认), "chord"(弓形), "arc"(弧形)
state画布对象状态,可以是"normal", "disabled", "hidden"(隐藏)
tags画布对象标签
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方法

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方法

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方法

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
buttround
projectingbevel
roundmiter

create_oval方法

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_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_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方法

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方法

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方法

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("<Left>", self.move_left) #按左键执行self.move_left
        root.bind("<Right>", 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()

3 tkinter子模块

上面讲述的组件,只需要导入tkinter就能使用。tkinter还提供了一些子模块,你需要导入它们来使用它们提供的一些拓展的功能。

3.1 tkinter.constants

这个模块中存储了一些常用变量,在给组件指定一些参数的时候会用到。比如设置组件的relief参数,可以设为"flat", "groove"等。constants里面就有两个变量FLAT="flat", GROOVE = "groove"。这些字符串全部大写作为变量名。因此如果导入了这个模块的全部内容,Scale(root, orient="vertical")也可写作Scale(root, orient=VERTICAL)

这样做可能是为了方便拼写检查,减少错误。有些编辑器对于不存在的变量会进行突出显示,如果拼写出错了会一目了然看出来。而使用字符串的话就不便看出错误的地方。

tkinter主模块中导入了constants模块的所有内容,这意味着你不需要导入这个模块也能在主模块中使用它们。调用了from tkinter import *即可直接使用里面的常量。

3.2 tkinter.messagebox

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"
askokcancelTrue或False
askyesnoTrue或False
askyesnocancelTrue或False或None
askretrycancelTrue或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("退出")

3.3 tkinter.filedialog 

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()

3.4 tkinter.colorchooser

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颜色对话框的标题

3.5 tkinter.ttk

参考资料: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组件功能的不同。

  • ttk组件共有参数只有:class_, cursor(光标样式), takefocus(是否获取焦点), style(样式)几个参数。
  • 部分组件不支持颜色方面的参数,比如Button不能设置background等参数,而Label等一部分组件仍然支持。
  • 参数不支持缩写,比如-validatecommand不能写成-vcmd,-background不能写成-bg。
  • -state参数不再支持,但是处于兼容的考虑,暂时没有变动这个参数。关于状态设置,ttk.Widget增加了两个相关的方法state和instate。
  • -padx和-pady参数合并为-padding参数,可以提供一个列表表示[左,上,右,下]的内部留白或是一个整数。Label, Button, Frame等组件支持。
  • 单选框和多选框的-indicatoron参数不再受支持,但可以通过把style参数设置为"Toolbutton"来实现按钮式选框。即:
    Checkbutton(style="Toolbutton")
    Radiobutton(style="Toolbutton")
  • 单选框、多选框和按钮的-anchor参数被移除。
  • -compound参数增加了"text"和"image"两个可选值,这么设置分别表示:只显示文本;只显示图片。
  • -bitmap参数被移除。
  • Scale组件不再支持-label参数。如果想要定义带标签的Scale,应使用ttk.LabeledScale组件。
  • 当按下Spinbox组件的上、下调节按钮时,分别会生成两个虚拟事件<<Increment>>和<<Decrement>>。

组件风格的区别

下面的列表中展示了tkinter主模块组件样式,和ttk中相同组件名的组件样式(均使用默认样式)。部分样式没有太大区别的组件没有包括在表格中。当鼠标移动到ttk组件上时,样式会发生变化,比较美观。ttk不是很美观的地方在于获取焦点后,部分组件会出现一个虚线框。

组件名

tkinter主模块中

tkinter.ttk中

Button
Checkbutton
Entry
Menubutton
Radiobutton
Scale(ttk.LabeledScale)
Spinbox

组件状态

ttk.Widget增加了一些特殊的方法,用来操作组件的状态。ttk的状态表示为一个序列,里面包含了多个状态的标志,比如("disabled", "focus")。下面是ttk可以设置的状态标志。如果在不支持某个状态标志的组件上设置了此标志,那么不会有任何效果。

注意:ttk的组件状态和普通tkinter组件的状态不一样!

状态解释
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传递给该回调函数。

3.6 ttk.Style

参考资料: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)获取或设置当前主题

configure方法

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方法

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"的效果。

Element(元素)

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方法

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。 

Theme(主题)

参考资料:TkDocs Tutorial - Styles and Themes

如果将多个对组件样子的设置集中到一起,就形成了主题。计算机系统有一些内置主题,它们是"alt", "default", "clam", "classic"。Mac系统还有一个额外的主题"aqua",Windows则还有"vista", "winxpnative"(或"xpnative")和"winnative"。

theme_use方法用来设置或获取当前主题,主题设置时,会刷新所有的组件,并发送一个虚拟事件<<ThemeChanged>>。下面是不同内置主题的组件样式。

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()

3.7 ttk.Combobox

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)设置组件的值

创建Combobox

from tkinter import *
from tkinter import ttk

root = Tk()

box = ttk.Combobox(root, values=("中文-English", "English-中文"))
box.pack()

mainloop()

虚拟事件<<ComboboxSelected>>

当下拉列表中的内容被选取时,会向Combobox发送一个虚拟事件<<ComboboxSelected>>。

from tkinter import *
from tkinter import ttk

root = Tk()

box = ttk.Combobox(root, values=("中文-English", "English-中文"))
box.pack()
box.bind("<<ComboboxSelected>>", lambda e: print("选取了", box.get()))

mainloop()

3.8 ttk.Separator

Separator组件显示一个分割线的图案,用于美化界面。

Separator(master=None, **kw)

参数作用
orient设置分割线的朝向,可以是"horizontal", "vertical",默认是水平

创建Separator

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()

可以发现,分割线很好地起到了分隔、美化界面的作用。

3.9 ttk.Sizegrip

Sizegrip组件在屏幕上添加一个拖动柄,用于调节窗口的大小。

Sizegrip(master=None, **kw)

此组件除了来自ttk.Widget的方法外,没有别的参数或方法。

创建Sizegrip

from tkinter import *
from tkinter.ttk import *

root = Tk()

sg = Sizegrip(root)
sg.pack(side="bottom", anchor="e", padx=20, pady=20) #靠左下角排放

mainloop()

3.10 ttk.Notebook

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的快捷键,调用后会为组件添加绑定事件:

<Control-Tab>:选中后一个选项卡

<Shift-Control-Tab>:选中前一个选项卡

<Alt-...>:选中设置了下划线的文字与按键相符的选项卡

创建Notebook

from tkinter import *
from tkinter.ttk import *

root = Tk()

note = Notebook(root)
note.pack()

mainloop()

这段代码创建一个空的Notebook,里面什么内容也没有。

add方法

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的选项卡,可以有以下方式。

  • 添加的Frame的名称。
  • 0到选项卡总数之间的一个整数。
  • "@x, y"形式来表示。
  • "current"(当前选中页面)和"end"(选项卡数量)。

虚拟事件<<NotebookTabChanged>>

当选项卡的选中变化时,会生成虚拟事件<<NotebookTabChanged>>。

3.11 ttk.Progressbar

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()停止自动增加

创建Progressbar

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方法

start和stop方法分别用于开始和结束进度条的自动增加。当进度条加载完时,会回到开头继续加载。

mode参数

mode参数用于设定进度条的模式。determinate模式下,进度条会不断增加。而indeterminate模式下,进度条会显示成一个小方块,在进度条的槽中来回运动。默认的模式是determinate,效果如下。

indeterminate模式效果如下。

一般,我们在知道进度条要加载的进度时会选用默认的模式,而不知道进度的时候会选用第二种模式。

3.12 ttk.Treeview

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,所以还支持两个方向的滚动条方法。 

创建Treeview

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方法

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方法

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组件会引发如下虚拟事件:

事件条件
<<TreeviewSelect>>Treeview的选中项目改变
<<TreeviewOpen>>当焦点所在项的子项展开(open=True)
<<TreeviewClose>>当焦点所在项的子项合并(open=False)

3.13 tkinter.font

Font类

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类,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')

载入目录下的字体文件

tkinter本身不支持载入字体文件,而只能使用系统字体。不过可以使用第三方pyglet模块载入。这并不是个好方法,非特殊情况不应该使用。先安装pyglet:

pip install pyglet

代码如下所示: 

from tkinter import *
import pyglet

fontfile = "Ma Shan Zheng Regular.ttf"
pyglet.options["win32_gdi_font"] = True
pyglet.font.add_file(fontfile)

root = Tk()

Label(root, text="这是一段使用ttf的文本", font=("Ma Shan Zheng", 14)).pack()
"""注意:传递给font的字体名称应为该字体本身的名称,而不是该字体的文件名"""

mainloop()

 这种方法存在许多缺点。比如:只能使用字体名称传递给font

3.14 tkinter.scrolledtext

scrolledtext模块中提供了一个ScrolledText类,继承自Text。和Text不同的是,这个组件在外观上多了一个y方向的滚动条。其他使用方法与Text一致。如果想要制作带有滚动条的Text,使用这个组件可以方便许多。

3.15 更多子模块

以上介绍的这些子模块都是最为常用的。除了这些以外,tkinter还有以下子模块。

子模块描述
commondialog提供了调用tk对话框的基类;功能已被messagebox, filedialog等替代
dialog提供了一个对话框,可设置标题,提示语,按钮等;样式较为简陋
dnd用于实现组件拖拽移动功能;该模块是实验性的,后期会被替代
simpledialog提供了一些询问字符串、整数等类型的对话框;样式较为简陋,而且是英文版的
tix提供了一些拓展组件;如今比较过时,可用ttk替代

附录1 关于tkinter的网站

Python官网(tkinter模块):tkinter —— Tcl/Tk 的 Python 接口 — Python 3.10.5 文档https://docs.python.org/zh-cn/3/library/tkinter.html#module-tkintericon-default.png?t=N7T8https://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/tkintericon-default.png?t=N7T8https://github.com/python/cpython/tree/3.10/Lib/tkinter

Tcl/Tk主页:Tcl Developer Sitehttps://www.tcl.tk/icon-default.png?t=N7T8https://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/icon-default.png?t=N7T8http://tkdocs.com/

附录2 调用Tcl/Tk命令

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节。

附录3 颜色列表

由于篇幅有限,将tkinter所有支持的颜色(不包括SystemButtonFace那种类型的系统颜色)放在此PDF文件中:tkinter/tk_colors.pdf · Python-ZZY/CSDN-articles - Gitee.com

如果你在开发Python tkinter程序时遇到了问题,或是有文章内容的建议,可以私信联系我,感谢支持!

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐