tkinter —— Tcl/Tk 的 Python 接口¶
tkinter 包 ("Tk 接口") 是针对 Tcl/Tk GUI 工具包的标准 Python 接口。 Tk 和 tkinter 在大多数 Unix 平台,包括 macOS,以及 Windows 系统上均可使用。
若在命令行执行 python -m tkinter,应会弹出一个简单的 Tk 界面窗口, 表明 tkinter 包已安装完成,还会显示当前安装的 Tcl/Tk 版本,以便阅读对应版本的 Tcl/Tk 文档。
也參考
- TkDocs
关于使用 Tkinter 创建用户界面的详细教程。 讲解了关键概念,并介绍了使用现代 API 的推荐方式。
- Tkinter 8.5 参考手册:一种 Python GUI
详细讲解可用的类、方法和选项的 Tkinter 8.5 参考文档。
Tcl/Tk 资源:
书籍:
- Modern Tkinter for Busy Python Developers
Mark Roseman 著。 (ISBN 978-1999149567)
- Python and Tkinter Programming
Alan Moore 著。 (ISBN 978-1788835886)
- 使用 Python 编程
Mark Lutz 著;对 Tkinter 进行了精彩的讲解。 (ISBN 978-0596158101)
- Tcl and the Tk Toolkit (2nd edition)
John Ousterhout ,Tcl/Tk 的创造者,与 Ken Jones 合著;未涉及 Tkinter。 (ISBN 978-0321336330)
Tkinter 模块¶
对 Tkinter 的支持分布在多个模块中。 大多数应用程序将需要主模块 tkinter,以及 tkinter.ttk 模块,后者提供了带主题的现代部件集及相应的 API:
from tkinter import *
from tkinter import ttk
-
class
tkinter.Tk(screenName=None, baseName=None, className='Tk', useTk=True, sync=False, use=None)¶ 构造一个最高层级的 Tk 部件,这通常是一个应用程序的主窗口,并为这个部件初始化 Tcl 解释器。 每个实例都有其各自所关联的 Tcl 解释器。
Tk类通常全部使用默认值来初始化。 不过,目前还可识别下列关键字参数:- screenName
当(作为字符串)给出时,设置
DISPLAY环境变量。 (仅限 X11)- baseName
预置文件的名称。 在默认情况下,baseName 是来自于程序名称 (
sys.argv[0])。- className
控件类的名称。 会被用作预置文件同时也作为 Tcl 唤起的名称 (interp 中的 argv0)。
- useTk
如果为
True,则初始化 Tk 子系统。tkinter.Tcl()函数会将其设为False。- sync
如果为
True,则同步执行所有 X 服务器命令,以便立即报告错误。 可被用于调试。 (仅限 X11)- use
指定嵌入应用程序的窗口 id,而不是将其创建为独立的顶层窗口。 id 必须以与顶层控件的 -use 选项值相同的方式来指定(也就是说,它具有与
winfo_id()的返回值相同的形式)。请注意在某些平台上只有当 id 是指向一个启用了 -container 选项的 Tk 框架或顶层窗口时此参数才能正确生效。
Tk读取并解释预置文件,其名称为.className.tcl和.baseName.tcl,进入 Tcl 解释器并基于.className.py在.baseName.py的内容调用exec()。 预置文件的路径为HOME环境变量,或者如果它未被设置,则为os.curdir。
-
tkinter.Tcl(screenName=None, baseName=None, className='Tk', useTk=False)¶ Tcl()函数是一个工厂函数,它创建的对象类似于Tk类创建的,只是不会初始化 Tk 子系统。这在调动 Tcl 解释器时最为有用,这时不想创建多余的顶层窗口,或者无法创建(比如不带 X 服务的 Unix/Linux 系统)。由Tcl()创建的对象可调用loadtk()方法创建一个顶层窗口(且会初始化 Tk 子系统)。
提供 Tk 支持的模块包括:
tkinter主 Tkinter 模块。
tkinter.colorchooser让用户选择颜色的对话框。
tkinter.commondialog本文其他模块定义的对话框的基类。
tkinter.filedialog允许用户指定文件的通用对话框,用于打开或保存文件。
tkinter.font帮助操作字体的工具。
tkinter.messagebox访问标准的 Tk 对话框。
tkinter.scrolledtext内置纵向滚动条的文本组件。
tkinter.simpledialog基础对话框和一些便捷功能。
tkinter.ttk在 Tk 8.5 中引入的带主题的控件集,提供了对应于
tkinter模块中许多经典控件的现代替代。
附加模块:
_tkinter一个包含低层级 Tcl/Tk 接口的二进制模块。 它会被主
tkinter模块自动导入,且永远不应被应用程序员所直接使用。 它通常是一个共享库(或 DLL),但在某些情况下可能被动态链接到 Python 解释器。idlelibPython 的集成开发与学习环境(IDLE)。 基于
tkinter。tkinter.constants当向 Tkinter 调用传入各种形参时可被用来代替字符串的符号常量。 由主
tkinter模块自动导入。tkinter.dnd针对
tkinter的(实验性的)拖放支持。 当以 Tk DND 代替时它将会被弃用。tkinter.tix(已弃用)一个增加了部分新控件的较老的第三方 Tcl/Tk 包。 对多数人来说可以在
tkinter.ttk中找到更好的替代品。turtleTk 窗口中的海龟绘图库。
Tkinter 拾遗¶
本节不应作为 Tk 或 Tkinter 的详尽教程。而只是一个补充,提供一些系统指南。
致谢:
Tk 是 John Ousterhout 在伯克利大学时写的。
Tkinter 是由 Steen Lumholt 和 Guido van Rossum 编写的。
本拾遗由弗吉尼亚大学的 Matt Conway 撰写。
HTML 渲染和一些自由编辑功能,是由 Ken Manheimer 根据 FrameMaker 创建的。
Fredrik Lundh 认真研究并修改了类的接口描述,使其与 Tk 4.2 保持一致。
Mike Clarkson 将文档转换为 LaTeX 格式,并编写了参考手册的用户界面章节。
本节内容的用法¶
本节分为两部分:前半部分(大致)涵盖了背景材料,后半部分可以作为手头的参考手册。
当试图回答“如何才能怎么怎么”这种问题时,通常最好是弄清楚如何直接在 Tk 中实现,然后转换回相应的 tkinter 调用。Python 程序员通常可查看 Tk 文档来猜测正确的 Python 命令。这意味着要用好 Tkinter,必须对 Tk 有一定的了解。本文无法完成这个任务,所以最好的做法就是给出目前最好的文档。下面给出一些小提示:
作者强烈建议用户先拿到一份 Tk 手册。具体来说,
manN目录下的 man 文档是最有用的。man3的 man 文档描述了 Tk 库的 C 接口,因此对脚本编写人员没有什么特别的帮助。Addison-Wesley 出版了一本名为《Tcl 和 Tk 工具包》的书,作者是 John Ousterhout(ISBN 0-201-63337-X),对于新手来说,这是一本很好的 Tcl 和Tk 介绍书籍。该书不算详尽,很多细节还是要看 man 手册。
对大多数人而言,
tkinter/__init__.py是最后一招,但其他手段都无效时也不失为一个好去处。
简单的 Hello World 程序¶
import tkinter as tk
class Application(tk.Frame):
def __init__(self, master=None):
super().__init__(master)
self.master = master
self.pack()
self.create_widgets()
def create_widgets(self):
self.hi_there = tk.Button(self)
self.hi_there["text"] = "Hello World\n(click me)"
self.hi_there["command"] = self.say_hi
self.hi_there.pack(side="top")
self.quit = tk.Button(self, text="QUIT", fg="red",
command=self.master.destroy)
self.quit.pack(side="bottom")
def say_hi(self):
print("hi there, everyone!")
root = tk.Tk()
app = Application(master=root)
app.mainloop()
Tcl/Tk 速览¶
类的层次结构看起来很复杂,但在实际操作中,应用程序编写人员几乎总是查看最底层的类。
註解:
提供这些类,是为了能在同一个命名空间下将某些功能组织在一起。并不意味着可以独立对其进行实例化。
Tk类在同一个应用程序中仅需作一次实例化。应用程序编程人员不需要显式进行实例化,只要有其他任何类被实例化,系统就会创建一个。Widget类不是用来实例化的,它仅用于继承以便生成“真正”的部件( C++ 中称为“抽象类”)。
若要充分利用这些参考资料,有时需要知道如何阅读 Tk 的短文,以及如何识别 Tk 命令的各个部分。(参见 将简单的 Tk 映射到 Tkinter 一节,了解以下内容在 tkinter 中的对应部分)。
Tk 脚本就是 Tcl 程序。像所有其他的 Tcl 程序一样,Tk 脚本只是由空格分隔的单词列表。一个Tk 部件只是它的 class,options 用于进行配置,actions 让它执行有用的动作。
要在 Tk 中制作一个部件,总是采用如下格式的命令:
classCommand newPathname options
- classCommand
表示要制作何种部件(按钮、标签、菜单......)。
- newPathname
该组件的新名字。Tk 中的所有名字都必须唯一。为了帮助实现这一点,Tk 中的部件都用 路径 命名,就像文件系统中的文件一样。顶层的部件,即 根,名为
.``(句点),而子部件则由更多的句点分隔。比如部件名可能会是 ``.myApp.controlPanel.okButton。- options
配置部件的外观,有时也能配置行为。这些选项以标志和值的列表形式出现。标志前带一个“-”,就像 Unix shell 命令的标志一样,如果值超过一个单词,就用引号括起来。
例如:
button .fred -fg red -text "hi there"
^ ^ \______________________/
| | |
class new options
command widget (-opt val -opt val ...)
一旦创建成功,部件的路径名就成了一条新的命令。这个新的 部件命令 是程序员让新部件执行某些 action 的句柄。在 C 语言中可表示为someAction(fred, someOptions),在 C++ 中可表示为fred.someAction(someOptions),而在 Tk 中写作:
.fred someAction someOptions
请注意,对象名 .fred 是以句点开头的。
如您所料,someAction 的可用值取决于部件的类别。如果 fred 为按钮,则 .fred disable 有效(fred 会变灰),而当 fred 为标签时则无效(Tk 不支持标签的禁用)。
someOptions 的合法值取决于动作。有些动作不需要参数,比如 disable,其他动作如文本输入框的 delete 命令则需用参数指定要删除的文本范围。
将简单的 Tk 映射到 Tkinter¶
Tk 中的类命令对应于 Tkinter 中的类构造函数:
button .fred =====> fred = Button()
父对象是隐含在创建时给定的新名字中的。在 Tkinter 中,父对象是显式指定的:
button .panel.fred =====> fred = Button(panel)
Tk 中的配置项是以连字符标签列表的形式给出的,后跟着参数值。在 Tkinter 中,选项指定为实例构造函数中的关键字参数,在配置调用时指定为关键字 args,或在已有实例中指定为实例索引,以字典的形式。参见 可选配置项 一节的选项设置部分。
button .fred -fg red =====> fred = Button(panel, fg="red")
.fred configure -fg red =====> fred["fg"] = red
OR ==> fred.config(fg="red")
在 Tk 中, 要在某个部件上执行动作, 要用部件名作为命令, 并后面附上动作名称, 可能还会带有参数(option)。在 Tkinter 中,则调用类实例的方法来执行部件的动作。部件能够执行的动作(方法)列在 tkinter/__init__.py 中。
.fred invoke =====> fred.invoke()
若要将部件交给打包器(geometry manager),需带上可选参数去调用 pack。在 Tkinter 中,Pack 类拥有全部这些功能,pack 命令的各种形式都以方法的形式实现。 tkinter 中的所有部件都是从 Packer 继承而来的,因此继承了所有打包方法。关于Form geometry manager 的更多信息,请参见 tkinter.tix 模块的文档。
pack .fred -side left =====> fred.pack(side="left")
快速参考¶
可选配置项¶
配置参数可以控制组件颜色和边框宽度等。可通过三种方式进行设置:
- 在对象创建时,使用关键字参数
fred = Button(self, fg="red", bg="blue")
- 在对象创建后,将参数名用作字典索引
fred["fg"] = "red" fred["bg"] = "blue"
- 利用 config() 方法修改对象的多个属性
fred.config(fg="red", bg="blue")
关于这些参数及其表现的完整解释,请参阅 Tk 手册中有关组件的 man 帮助页。
请注意,man 手册页列出了每个部件的“标准选项”和“组件特有选项”。前者是很多组件通用的选项列表,后者是该组件特有的选项。标准选项在 options(3) man 手册中有文档。
本文没有区分标准选项和部件特有选项。有些选项不适用于某类组件。组件是否对某选项做出响应,取决于组件的类别;按钮组件有一个 command 选项,而标签组件就没有。
组件支持的选项在其手册中有列出,也可在运行时调用 config() 方法(不带参数)查看,或者通过调用组件的 keys() 方法进行查询。这些调用的返回值为字典,字典的键是字符串格式的选项名(比如 'relief'),字典的值为五元组。
有些选项,比如 bg 是全名通用选项的同义词(bg 是 “background”的简写)。向 config() 方法传入选项的简称将返回一个二元组,而不是五元组。传回的二元组将包含同义词的全名和“真正的”选项(比如 ('bg', 'background'))。
索引 |
含意 |
示例 |
|---|---|---|
0 |
选项名称 |
|
1 |
数据库查找的选项名称 |
|
2 |
数据库查找的选项类 |
|
3 |
默认值 |
|
4 |
当前值 |
|
示例:
>>> print(fred.config())
{'relief': ('relief', 'relief', 'Relief', 'raised', 'groove')}
当然,输出的字典将包含所有可用选项及其值。这里只是举个例子。
包装器¶
包装器是 Tk 的形状管理机制之一。 形状(geometry )管理器用于指定多个部件在容器(共同的 主 组件)内的相对位置。与更为麻烦的 定位器 相比(不太常用,这里不做介绍),包装器可接受定性的相对关系—— 上面 、左边 、填充 等,并确定精确的位置坐标。
主 部件的大小都由其内部的 “从属部件” 的大小决定。包装器用于控制从属部件在主部件中出现的位置。可以把部件包入框架,再把框架包入其他框架中,搭建出所需的布局。此外,只要完成了包装,组件的布局就会进行动态调整,以适应布局参数的变化。
请注意,只有用形状管理器指定几何形状后,部件才会显示出来。忘记设置形状参数是新手常犯的错误,惊讶于创建完部件却啥都没出现。部件只有在应用了类似于打包器的 pack() 方法之后才会显示在屏幕上。
调用 pack() 方法时可以给出由关键字/参数值组成的键值对,以便控制组件在其容器中出现的位置,以及主程序窗口大小变动时的行为。下面是一些例子:
fred.pack() # defaults to side = "top"
fred.pack(side="left")
fred.pack(expand=1)
包装器的参数¶
关于包装器及其可接受的参数,更多信息请参阅 man 手册和 John Ousterhout 书中的第 183 页。
- anchor
anchor 类型。 表示包装器要放置的每个从属组件的位置。
- expand
布尔型,
0或1。- fill
合法值为:
'x'、'y'、'both'、'none'。- ipadx 和 ipady
距离值,指定从属部件的内边距。
- padx 和 pady
距离值,指定从属部件的外边距。
- side
合法值为:
'left'、'right'、'top'、'bottom'。
部件与变量的关联¶
通过一些特定参数,某些组件(如文本输入组件)的当前设置可直接与应用程序的变量关联。这些参数包括 variable 、 textvariable 、 onvalue 、 offvalue 、 value。这种关联是双向的:只要这些变量因任何原因发生变化,其关联的部件就会更新以反映新的参数值。
不幸的是,在目前 tkinter 的实现代码中,不可能通过 variable 或 textvariable 参数将任意 Python 变量移交给组件。变量只有是 tkinter 中定义的 Variable 类的子类,才能生效。
已经定义了很多有用的 Variable 子类: StringVar 、 IntVar 、DoubleVar 和 BooleanVar。调用 get() 方法可以读取这些变量的当前值;调用 set() 方法则可改变变量值。只要遵循这种用法,组件就会保持跟踪变量的值,而不需要更多的干预。
例如:
import tkinter as tk
class App(tk.Frame):
def __init__(self, master):
super().__init__(master)
self.pack()
self.entrythingy = tk.Entry()
self.entrythingy.pack()
# Create the application variable.
self.contents = tk.StringVar()
# Set it to some value.
self.contents.set("this is a variable")
# Tell the entry widget to watch this variable.
self.entrythingy["textvariable"] = self.contents
# Define a callback for when the user hits return.
# It prints the current value of the variable.
self.entrythingy.bind('<Key-Return>',
self.print_contents)
def print_contents(self, event):
print("Hi. The current entry content is:",
self.contents.get())
root = tk.Tk()
myapp = App(root)
myapp.mainloop()
窗口管理器¶
Tk 有个实用命令 wm,用于与窗口管理器进行交互。wm 命令的参数可用于控制标题、位置、图标之类的东西。在 tkinter 中,这些命令已被实现为 Wm 类的方法。顶层部件是 Wm 类的子类,所以可以直接调用 Wm 的这些方法。
要获得指定部件所在的顶层窗口,通常只要引用该部件的主窗口即可。当然,如果该部件是包装在框架内的,那么主窗口不代表就是顶层窗口。为了获得任意组件所在的顶层窗口,可以调用 _root() 方法。该方法以下划线开头,表明其为 Python 实现的代码,而非 Tk 提供的某个接口。
以下是一些典型用法:
import tkinter as tk
class App(tk.Frame):
def __init__(self, master=None):
super().__init__(master)
self.pack()
# create the application
myapp = App()
#
# here are method calls to the window manager class
#
myapp.master.title("My Do-Nothing Application")
myapp.master.maxsize(1000, 400)
# start the program
myapp.mainloop()
Tk 参数的数据类型¶
- anchor
合法值是罗盘的方位点:
"n"、"ne"、"e"、"se"、"s"、"sw"、"w"、"nw"和"center"。- bitmap
内置已命名的位图有八个:
'error'、'gray25'、'gray50'、'hourglass'、'info'、'questhead'、'question'、'warning'。若要指定位图的文件名,请给出完整路径,前面加一个@,比如"@/usr/contrib/bitmap/gumby.bit"。- boolean
可以传入整数 0 或 1,或是字符串
"yes"或"no"。- callback -- 回调
指任何无需调用参数的 Python 函数。 例如:
def print_it(): print("hi there") fred["command"] = print_it
- color
可在 rgb.txt 文件中以颜色名的形式给出,或是 RGB 字符串的形式,4 位 :
"#RGB",8 位 :"#RRGGBB",12 位:"#RRRGGGBBB",16 位:"#RRRRGGGGBBBB",其中R、G、B 为合法的十六进制数值。 详见 Ousterhout 书中的第 160 页。- cursor
可采用
cursorfont.h中的标准光标名称,去掉XC_前缀。 比如要获取一个手形光标(XC_hand2),可以用字符串"hand2"。也可以指定自己的位图和掩码文件作为光标。参见 Ousterhout 书中的第 179 页。- distance
屏幕距离可以用像素或绝对距离来指定。像素是数字,绝对距离是字符串,后面的字符表示单位:
c是厘米,i是英寸,m是毫米,p则表示打印机的点数。例如,3.5 英寸可表示为"3.5i"。- font
Tk 采用一串名称的格式表示字体,例如
{courier 10 bold}。正数的字体大小以点为单位,负数的大小以像素为单位。- geometry
这是一个
widthxheight形式的字符串,其中宽度和高度对于大多数部件来说是以像素为单位的(对于显示文本的部件来说是以字符为单位的)。例如:fred["geometry"] = "200x100"。- justify
合法的值为字符串:
"left"、"center"、"right"和"fill"。- 区域
这是包含四个元素的字符串,以空格分隔,每个元素是表示一个合法的距离值(见上文)。例如:
"2 3 4 5"、"3i 2i 4.5i 2i"和"3c 2c 4c 10.43c"都是合法的区域值。- relief
决定了组件的边框样式。 合法值包括:
"raised"、"sunken"、"flat"、"groove"和"ridge"。- scrollcommand
这几乎就是带滚动条部件的
set()方法,但也可是任一只有一个参数的部件方法。- wrap
只能是以下值之一:
"none"、"char"、"word"。
绑定和事件¶
部件命令中的 bind 方法可觉察某些事件,并在事件发生时触发一个回调函数。bind 方法的形式是:
def bind(self, sequence, func, add=''):
其中:
- sequence
是一个表示事件的目标种类的字符串。(详情请看 bind 的手册页和 John Outsterhout 的书的第 201 页。)
- func
是带有一个参数的 Python 函数,发生事件时将会调用。传入的参数为一个 Event 实例。(以这种方式部署的函数通常称为 回调函数。)
- add
可选项,
''或'+'。传入空字符串表示本次绑定将替换与此事件关联的其他所有绑定。传递'+'则意味着加入此事件类型已绑定函数的列表中。
例如:
def turn_red(self, event):
event.widget["activeforeground"] = "red"
self.button.bind("<Enter>", self.turn_red)
请注意,在 turn_red() 回调函数中如何访问事件的 widget 字段。该字段包含了捕获 X 事件的控件。下表列出了事件可供访问的其他字段,及其在 Tk 中的表示方式,这在查看 Tk 手册时很有用处。
Tk |
Tkinter 事件字段 |
Tk |
Tkinter 事件字段 |
|---|---|---|---|
%f |
focus |
%A |
char |
%h |
height |
%E |
send_event |
%k |
keycode |
%K |
keysym |
%s |
state |
%N |
keysym_num |
%t |
time |
%T |
type |
%w |
width |
%W |
widget |
%x |
x |
%X |
x_root |
%y |
y |
%Y |
y_root |
index 参数¶
很多控件都需要传入 index 参数。该参数用于指明 Text 控件中的位置,或指明 Entry 控件中的字符,或指明 Menu 控件中的菜单项。
- Entry 控件的索引(index、view index 等)
Entry 控件带有索引属性,指向显示文本中的字符位置。这些
tkinter函数可用于访问文本控件中的这些特定位置:- Text 控件的索引
Text 控件的索引语法非常复杂,最好还是在 Tk 手册中查看。
- Menu 索引(menu.invoke()、menu.entryconfig() 等)
菜单的某些属性和方法可以操纵特定的菜单项。只要属性或参数需要用到菜单索引,就可用以下方式传入:
一个整数,指的是菜单项的数字位置,从顶部开始计数,从 0 开始;
字符串
"active",指的是当前光标所在的菜单;字符串
"last",指的是上一个菜单项;带有
@前缀的整数,比如@6,这里的整数解释为菜单坐标系中的 y 像素坐标;表示没有任何菜单条目的字符串
"none"经常与 menu.activate() 一同被用来停用所有条目,以及 ——与菜单项的文本标签进行模式匹配的文本串,从菜单顶部扫描到底部。请注意,此索引类型是在其他所有索引类型之后才会考虑的,这意味着文本标签为
last、active或none的菜单项匹配成功后,可能会视为这些单词文字本身。
图片¶
通过 tkinter.Image 的各种子类可以创建相应格式的图片:
BitmapImage对应 XBM 格式的图片。PhotoImage对应 PGM、PPM、GIF 和 PNG 格式的图片。后者自 Tk 8.6 开始支持。
这两种图片可通过 file 或 data 属性创建的(也可能由其他属性创建)。
然后可在某些支持 image 属性的控件中(如标签、按钮、菜单)使用图片对象。这时,Tk 不会保留对图片对象的引用。当图片对象的最后一个 Python 引用被删除时,图片数据也会删除,并且 Tk 会在用到图片对象的地方显示一个空白框。
也參考
Pillow 包增加了对 BMP、JPEG、TIFF 和 WebP 等格式的支持。
文件处理程序¶
Tk 允许为文件操作注册和注销一个回调函数,当对文件描述符进行 I/O 时,Tk 的主循环会调用该回调函数。每个文件描述符只能注册一个处理程序。示例代码如下:
import tkinter
widget = tkinter.Tk()
mask = tkinter.READABLE | tkinter.WRITABLE
widget.tk.createfilehandler(file, mask, callback)
...
widget.tk.deletefilehandler(file)
在 Windows 系统中不可用。
由于不知道可读取多少字节,你可能不希望使用 BufferedIOBase 或 TextIOBase 的 read() 或 readline() 方法,因为这些方法必须读取预定数量的字节。 对于套接字,可使用 recv() 或 recvfrom() 方法;对于其他文件,可使用原始读取方法或 os.read(file.fileno(), maxbytecount)。
-
Widget.tk.createfilehandler(file, mask, func)¶ 注册文件处理程序的回调函数 func。 file 参数可以是具备
fileno()方法的对象(例如文件或套接字对象),也可以是整数文件描述符。 mask 参数是下述三个常量的逻辑“或”组合。回调函数将用以下格式调用:callback(file, mask)
-
Widget.tk.deletefilehandler(file)¶ 注销文件处理函数。