25.1. tkinter — Tcl/Tk 的 Python 接口

源代码: Lib/tkinter/__init__.py

tkinter 库(“Tk 接口”)是 Tk GUI 工具包的标准 Python 接口。在大多数的 Unix 平台,以及 Windows 系统上均可以使用 Tk 和 tkinter(Tk 不是 Python 的一部分;它在 ActiveState 上被维护。)你可以通过在命令行中运行 python -m tkinter,来检查你是否已经在系统中正确安装tkinter ; 这将会打开一个窗口,演示一个简单的 Tk 界面。

另请参阅

Python Tkinter Resources
Python Tkinter 指南,提供了大量关于使用 Python 的 Tk 信息和其他 Tk 信息资源的链接。
TKDocs
大量介绍对于一些控件的界面友好性增强。
Tkinter参考:Python GUI
在线参考材料
来自effbot的Tkinter文档
effbot.org 提供的 tkinter 在线参考。
Tcl / Tk 手册
最新版本 tcl/tk 的官方手册。
编程Python
由 Mark Lutz 所写,很好地含盖了 Tkinter 。
给繁忙的Python开发人员的现代Tkinter
由 Mark Rozerman 撰写的关于使用 Python 和 Tkinter 构建有吸引力的现代图形用户界面的书。
Python和Tkinter程序设计
这本书由 John Grayson 所写 (ISBN 1-884777-81-3)。

25.1.1. Tkinter 模块

大多数情况下,tkinter模块有你所需要的一切,但一些附加的模块也会被用到。Tk 接口位于一个叫做_tkinter的二进制模块.这个模块包含了 Tk的底层接口, 但是不应该让应用程序直接调用它。它通常是共享库 (或 DLL),但在某些情况下可能会静态链接到Python 解释器。

除了 Tk 接口模块,tkinter 还包含了大量的 Python 模块,tkinter.constants 是最重要的模块之一。导入 tkinter 会自动导入 tkinter.constants,所以通常为了使用 Tkinter 你所需要做的就是一个简单的导入语句:

import tkinter

或者,更常用的做法是:

from tkinter import *
class tkinter.Tk(screenName=None, baseName=None, className='Tk', useTk=1)

Tk 没有参数被实例化。这将创建一个顶层的 Tk 窗口,通常是应用程序的主窗口。每个实例都有其自身相关联的 Tcl 解释器。

tkinter.Tcl(screenName=None, baseName=None, className='Tk', useTk=0)

Tcl() 函数是一个工厂函数,创造了一个像那样 Tk 类创建的对象,除了它不会初始化Tk 子系统。这个经常很有用,当驱动 Tcl 解释器在一个不希望创建外来顶层窗口的环境中,或一个不能创建的环境 (例如 Unix/Linux 系统没有 X 服务器)。一个通过 Tcl() 对象创建的对象,可以通过调用 loadtk() 方法是创建一个顶层窗口 (和 Tk 子系统初始化)。

其他提供 Tk 支持的模块包括︰

tkinter.scrolledtext
包含垂直滚动条的文本部件。
tkinter.colorchooser
可以让用户选择一种颜色的对话框。
tkinter.commondialog
在此处列出的其他模块中定义的对话框的的基类。
tkinter.filedialog
通用对话框允许用户指定要打开或保存的文件。
tkinter.font
可帮助处理字体的工具。
tkinter.messagebox
标准 Tk 对话框。
tkinter.simpledialog
基本对话框和方便的功能。
tkinter.dnd
tkinter支持拖放。这是实验性的,当替换为 Tk DND 时它应当被弃用。
turtle
Tk 窗口中的海龟绘图图形。

25.1.2. Tkinter Life Preserver

本节不是为 Tk 或 Tkinter 提供详尽的教程。相反,它旨在系统性地提供一些指导方向。

贡献:

  • Tk 是由 John Ousterhout 在伯克利时写的。
  • Tkinter 是由 Steen Lumholt 和 Guido van Rossum 写的。
  • 这个 Life Preserver 是由弗吉尼亚大学的 Matt Conway 写的。
  • HTML 页面和一些自由编辑,是用 Ken Manheimer 的 FrameMaker 版本生成的。
  • Fredrik Lundh 详细阐述和修改了类接口描述,使它们能与 Tk 4.2 兼容。
  • Mike Clarkson 将文档转换为 LaTeX,并编译了参考手册的用户界面一章。

25.1.2.1. 如何使用这部分

这部分设计分为两部分:前半部分(大致)涵盖相关资料,后半部分方便键盘输入运行参考。

当试图回答“如何做XX”的形式的问题时,通常最好先找出在纯 Tk 中如何做“XX”,然后将其转换回相应的 tkinter 调用。Python 程序员通常可以通过查看 Tk 文档来猜测正确的 Python 命令。这意味着,为了使用 Tkinter,你将不得不懂一点 Tk。这个文档不能充当这个角色,所以我们能做的,最好是给你指明已经存在的最好文档。这是一些提示:

  • 作者强烈建议获取 Tk 手册页的副本。特别是 manN 目录中的手册页最有用。man3 手册页描述了 Tk 库的 C 接口,因此对于写脚本不是特别有用。
  • Addison-Wesley 出版了一本面向初学者介绍 Tcl 和 Tk,由 John Ousterhout 写的名为 Tcl and the Tk Toolkit (ISBN 0-201-63337-X)的书籍。这本书并不详尽,对于许多细节,它要求参照手册。
  • tkinter/__init__.py 是最后手段,当找不到其它有效方法的时候,它是一个好的选择。

也可以看看

Tcl / Tk 8.6手册页
Tcl/Tk 手册访问 www.tcl.tk。
ActiveState Tcl主页
Tk/Tcl 开发主要在 ActiveState。
Tcl和Tk工具包
这本书由 Tcl 发明者 John Ousterhout 所写。
Tcl和Tk中的实际编程
Brent Welch’s 的百科书。

25.1.2.2. 一个简单的 Hello World 程序

import tkinter as tk

class Application(tk.Frame):
    def __init__(self, master=None):
        super().__init__(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=root.destroy)
        self.quit.pack(side="bottom")

    def say_hi(self):
        print("hi there, everyone!")

root = tk.Tk()
app = Application(master=root)
app.mainloop()

25.1.3. 快速了解 Tcl/Tk

类层次结构看起来很复杂,但在实践中,程序员几乎只是引用层次结构底部的类。

注:

  • 这些类是为了在一个命名空间下组织某些功能而提供的。它们不需要单独实例化。
  • Tk 类仅在应用程序中实例化一次。程序员不需要显式地实例化一个,只要任何其他类被实例化,系统就创建一个实例。
  • Widget 类并不意味着被实例化,它只是用于子类化来创建“真正的”控件(在 C++ 中,这被称为“抽象类”)。

为了使用这个参考资料,你可能需要知道如何阅读简短的 Tk 文章,以及如何识别 Tk 命令的各个部分。tkinter 与 Tk 代码的映射关系,请参阅将基本 Tk 映射到 Tkinter 部分)。

Tk 脚本是 Tcl 程序。像所有 Tcl 程序一样,Tk 脚本只是用空格分隔标记的列表。Tk 控件只是它的 classoptions 帮助配置,actions 使它做有用的事情的。

要在 Tk 中创建一个控件,命令总是以下形式:

classCommand newPathname options
classCommand
表示要创建控件的类型(按钮,标签,菜单...)
newPathname
表示新建的控件的名称。Tk 中的所有名称必须是唯一的。为了减少命名冲突,Tk 中的控件使用路径名命名,就像文件系统中的文件一样。顶级控件,也就是名字是 root 的那个控件,用 .(句号)导入,并且和子类之间用句号做分隔。例如,.myApp.controlPanel.okButton 可能是某个控件的名称。
选项
配置控件的外观,在某些情况下配置其行为。选项以标志和值的列表的形式出现。标志以 “ - ” 开头,类似 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 disable 如果 fred 是一个按钮控件(fred变灰色)是可行的,但如果 fred 是一个标签控件(Tk 中不支持禁用标签控件)就不能工作了。

someOptions 的值是否合法与 action 相关。某些 actions,如 disable,不需要任何参数,其他的,如文本输入框的 delete 命令,将需要参数来指定要删除的文本范围。

25.1.4. 将基本 Tk 映射到 Tkinter

Tk 中的类命令对应于 Tkinter 中的类结构。

button .fred                =====>  fred = Button()

Tk 控件所属主体在创建时就已经包含于名称中。在 Tkinter 中,要明确指定主体。

button .panel.fred          =====>  fred = Button(panel)

Tk 配置选项是连字符加标签,后跟值的列表。在 Tkinter 中,在实例构造中,选项被指定为关键字参数,对于已建立的实例,在字典样式中作为索引,或者设置方法的参数。有关设置选项,请参见设置选项一节。

button .fred -fg red        =====>  fred = Button(panel, fg="red")
.fred configure -fg red     =====>  fred["fg"] = red
                            OR ==>  fred.config(fg="red")

在 Tk 中,要对控件执行一个 action,使用控件名称作为命令,并跟随一个 action 名称,可能带有参数(选项)。在 Tkinter 中,用实例调用方法的形式来调用控件的 actions。已定义可执行的 actions (methods) ,可在 tkinter/__init__.py 中查看。

.fred invoke                =====>  fred.invoke()

要给 packer(几何管理器)增加一个控件,你可以调用可带参数的 pack。在 Tkinter 中,Pack 类保留所有这些功能,各种形式的 pack 命令被实现为方法。tkinter 中的所有控件都是从 Packer 中继承的,因此继承了所有 packing 的方法。有关表单几何管理器的其他信息,请参阅 tkinter.tix 模块文档。

pack .fred -side left       =====>  fred.pack(side="left")

25.1.6. 参考速查

25.1.6.1. 设置选项

选项控制像控件的颜色和边框宽度。选项可以通过三种方式设置:

在对象创建时,使用关键字参数
fred = Button(self, fg="red", bg="blue")
创建对象后,像字典索引一样处理选项名称
fred["fg"] = "red"
fred["bg"] = "blue"
在对象创建后使用 config() 方法更新多个设置
fred.config(fg="red", bg="blue")

有关给定选项及其行为的完整说明,请参阅相关控件的 Tk 手册页。

请注意,手册页列出了每个控件的“标准选项”和“控件特定选项”。前者是许多控件常见的选项列表,后者是某些控件特有的选项。标准选项记录在选项(3)手册页上。

在本文档中不对标准和特定控件选项进行区分。某些选项不适用于某些种类的控件。给定控件是否响应特定选项取决于控件的类;按钮具有 command 选项,标签就没有。

给定控件支持的选项在控件手册页中列出, 或者可以在运行时通过调用不带参数的 config() 方法或通过调用或通过调用 keys() 方法。这些调用返回的值是一个字典,其关键字是作为字符串的选项的名称(例如,'relief'),其值是 5 元组。

某些选项(例如 bg)是常用选项的同义缩写(bg是 “background” 的缩写)。通过传递 config() 方法,简写选项的名称将返回2元组,而不是5元组。传回的2元组将包含同义词的名称和“真实”选项(例如('bg', 'background'))。

指数含义例子
0选项名称'relief'
1数据库查找的选项名称'relief'
2数据库查找的选项类'Relief'
3默认值'raised'
4当前值'groove'

例子:

>>> print(fred.config())
{'relief': ('relief', 'relief', 'Relief', 'raised', 'groove')}

当然,打印的字典将包括所有可用的选项及其值。这仅仅是作为示例。

25.1.6.2. Packer

packer 是 Tk 的几何管理机制之一。几何管理器用于指定控件在其容器中的定位的相对定位 - 它们的共有主体相比于更复杂的 placer(这不太常见,我们在这里不涉及),packer 采用定性关系规范 - aboveto the left offilling等等 - 并且可以确定您的确切位置坐标。

任何 主体 控件的大小由“从属控件”的大小确定。packer 用于控制从属控件在所属主体内部出现的位置。您可以将控件封装成 frames,再将 frames 封装成其他 frames,以便实现所需的布局。此外,一旦被封装会被动态地调整以适应配置的增量变化。

请注意,如果不通过几何管理器指定了控件的几何位置,控件将不会出现。初学者经常会忘记说明控件的几何位置,然后会因创建了控件而控件并没有显示而困惑。只有设置了控件的几何位置,控件才会出现,例如,为它添加 packer 的 pack() 方法。

pack() 方法可以使用 关键字选项/值 的键值对来控制控件在其容器中显示的位置,以及调整主应用程序窗口大小时的行为方式。这里有些例子:

fred.pack()                     # defaults to side = "top"
fred.pack(side="left")
fred.pack(expand=1)

25.1.6.3. Packer 选项

有关 packer 的更多信息及其选项,请参阅手册页和 John Ousterhout 的书的第183页。

anchor(锚)
Anchor 类型。标示放在 packer 中每个从控件的位置。
expand(可拉伸)
布尔, 01.
fill(填充)
有效值: 'x''y''both''none'.
ipadx 和 ipady
距离 - 在从属控件的每一侧指定内边距。
padx和pady
距离 - 在从属控件的每一侧指定外边距。
side(方向)
有效值为: 'left''right''top''bottom'

25.1.6.4. 耦合控件变量

一些控件(如文本输入控件)的当前值设置可以通过使用特殊选项直接连接到应用程序变量。这些选项是 variabletextvariableonvalueoffvaluevalue此连接都是这样的工作方式:如果变量因任何原因更改,则其连接的控件将更新以反映新值。

不幸的是,在当前实现的 tkinter 中,不可能通过 variabletextvariable 选项将任意的 Python 变量提交给控件。唯一适用于这种变量是从tkinter中定义的变量类中子类化的变量。

有很多已经定义的有用子类变量:StringVarIntVarDoubleVarBooleanVar要读取这样一个变量的当前值,调用 get() 方法,改变它的值,调用 set() 方法。如果你遵循这个协议,控件将始终跟踪变量的值,您不用自己进一步干预。

例如:

class App(Frame):
    def __init__(self, master=None):
        super().__init__(master)
        self.pack()

        self.entrythingy = Entry()
        self.entrythingy.pack()

        # here is the application variable
        self.contents = 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

        # and here we get a callback when the user hits return.
        # we will have the program print out the value of the
        # application variable when the user hits return
        self.entrythingy.bind('<Key-Return>',
                              self.print_contents)

    def print_contents(self, event):
        print("hi. contents of entry is now ---->",
              self.contents.get())

25.1.6.5. 窗口管理器

在 Tk 中,有一个实用程序命令,wm,用于与窗口管理器交互。wm 命令的选项允许您控制诸如标题,位置,图标位图等内容。tkinter 中,这些命令已以 Wm 类的方法实现。顶级控件是从 Wm 类继承的,因此可以直接调用 Wm 方法。

要获取包含给定控件的顶级窗口,您通常只能参考控件的主体。当然,如果控件已经被封装在 frame 中,则主体将不表示顶层窗口。要获取任意控件的顶级窗口,可以调用 _root() 方法。此方法以下划线开始,表示此函数是实现的一部分,而不是 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()

25.1.6.6. Tk 选项数据类型

anchor(锚)
有效值是位置点:"n""ne""e""se""s""sw""w""nw""center"
bitmap(位图)
有八个内置的已命名位图:'error''gray25''gray50''hourglass''info''questhead''question''warning'要指定X位图文件名,给出文件的完整路径,前面加上 @,如"@/usr/contrib/bitmap/gumby.bit"
boolean(布尔)
您可以传递整数 0 或 1 或字符串 “yes”“no”
callback(回调)

回调函数可以是任何的没有参数的函数。例如:

def print_it():
    print("hi there")
fred["command"] = print_it
color(颜色)
Colors can be given as the names of X colors in the rgb.txt file, or as strings representing RGB values in 4 bit: "#RGB", 8 bit: "#RRGGBB", 12 bit” "#RRRGGGBBB", or 16 bit "#RRRRGGGGBBBB" ranges, where R,G,B here represent any legal hex digit. 有关详细信息,请参阅Ousterhout的书的第160页。
cursor(光标)
可以使用cursorfont.h的标准X游标名称,而不使用XC_前缀。例如,要获取手形光标(XC_hand2),请使用字符串"hand2"您还可以指定自己的位图和掩码文件。参见Ousterhout的书的第179页。
distance(距离)
屏幕距离可以指定像素或绝对距离。像素以数字和绝对距离作为字符串,尾随字符表示单位:c表示厘米,i表示英寸,m表示毫米,pFor example, 3.5 inches is expressed as "3.5i".
font(字体)
Tk使用列表字体名称格式,例如{courier 10 bold}具有正数的字体大小以点数测量;具有负数的尺寸以像素测量。
geometry(几何大小)
这是一种形式为widthxheight的字符串,其中对于大多数小部件(以显示文本的小部件的字符为单位),宽度和高度以像素为单位。例如:fred [“geometry”] = “200x100”
justify(对齐方式)
有效值是:"left""center""right""fill"
region(区域)
这是一个具有四个空格分隔元素的字符串,每个元素都是一个合法距离(见上文)。例如:“2 3 4 5”“3i 2i 4.5i 2i”“3c 2c 4c 10.43c“均为有效的区域。
relief
确定窗口小部件的边框样式。有效的值有:"raised", "sunken", "flat", "groove""ridge".
scrollcommand
这几乎总是一些滚动条小部件的set()方法,但可以是任何接受单个参数的widget方法。
wrap:
必须为以下之一:"none""char""word"

25.1.6.7. 绑定和事件

widget命令的bind方法允许您监视某些事件,并在发生事件类型时触发回调函数。绑定方法的形式是:

def bind(self, sequence, func, add=''):

参数依次为:

sequence
是表示事件的目标类型的字符串。(有关详细信息,请参阅John Ousterhout的书的bind手册页和第201页)。
func
是一个Python函数,使用一个参数,在事件发生时调用。事件实例将作为参数传递。(以这种方式部署的函数通常称为回调函数。)
add
可选参数,'''+'传递空字符串表示此绑定将替换此事件关联的任何其他绑定。传递'+'意味着此函数将添加到绑定到此事件类型的函数列表。

例如:

def turn_red(self, event):
    event.widget["activeforeground"] = "red"

self.button.bind("<Enter>", self.turn_red)

注意如何在turn_red()回调中访问事件的窗口小部件字段。此字段包含捕获X事件的窗口小部件。下表列出了您可以访问的其他事件字段及其在Tk中的表示方式,这在引用Tk手册页时很有用。

TkTkinter事件字段TkTkinter事件字段
%F焦点%一个char
%H高度%Esend_event
%k关键代码%Kkeysym
%s%Nkeysym_num
%t时间%T类型
%w宽度%W窗口小部件
%XX%Xx_root
%yy%Yy_root

25.1.6.8. 索引参数

许多小部件需要传递“索引”参数。这些用于指向文本窗口小部件中的特定位置,或者指向Entry小部件中的特定字符,或指向菜单窗口小部件中的特定菜单项。

条目窗口小部件索引(索引,视图索引等)
条目小部件具有指向正在显示的文本中的字符位置的选项。您可以使用这些tkinter函数在文本小部件中访问这些特殊点:
文本小部件索引
Text小部件的索引符号非常丰富,最好在Tk手册页中进行描述。
菜单索引(menu.invoke(),menu.entryconfig()等)

菜单的一些选项和方法操纵特定的菜单项。每当选项或参数需要菜单索引时,您可以传入:

  • 一个整数,指的是窗口小部件中条目的数字位置,从顶部开始,从0开始;
  • 字符串"active",其指当前在光标下的菜单位置;
  • 字符串"last",表示最后一个菜单项;
  • @前面的整数,如@6,其中整数被解释为菜单坐标系中的y像素坐标;
  • 字符串"none",这表示根本没有菜单项,最常用于menu.activate()来停用所有条目,最后,
  • 从菜单顶部到底部扫描的与菜单条目的标签匹配的文本字符串。注意,在所有其他之后考虑该索引类型,这意味着标记为lastactivenone的菜单项的匹配可以被解释作为上述字面值,而不是。

25.1.6.9. Images

位图/像素映射图像可以通过tkinter.Image的子类创建:

  • BitmapImage可用于X11位图数据。
  • PhotoImage可用于GIF和PPM / PGM颜色位图。

通过filedata选项(其他选项也可用)创建任一类型的图像。

然后,图像对象可以用于某些窗口小部件支持image选项的任何位置。标签,按钮,菜单)。在这些情况下,Tk不会保留对图像的引用。当对图像对象的最后一个Python引用被删除时,图像数据也被删除,并且Tk将在图像被使用的任何地方显示一个空框。

25.1.7. File Handlers

Tk允许您注册和取消注册一个回调函数,当在文件描述器上可能有I / O时,它将从Tk mainloop中调用。每个文件只能注册一个处理程序描述器。示例代码:

import tkinter
widget = tkinter.Tk()
mask = tkinter.READABLE | tkinter.WRITABLE
widget.tk.createfilehandler(file, mask, callback)
...
widget.tk.deletefilehandler(file)

此功能在Windows上不可用。

Since you don’t know how many bytes are available for reading, you may not want to use the BufferedIOBase or TextIOBase read() or readline() methods, since these will insist on reading a predefined number of bytes. 对于套接字,recv()recvfrom()方法将正常工作;对于其他文件,请使用原始读取或os.read(file.fileno(), maxbytecount)

Widget.tk.createfilehandler(file, mask, func)

注册文件处理程序回调函数func文件参数可以是具有fileno()方法(例如文件或套接字对象)的对象,也可以是整型文件描述器。掩码参数是以下三个常量中任何一个的ORed组合。回调的调用如下:

callback(file, mask)
Widget.tk.deletefilehandler(file)

取消注册文件处理程序。

tkinter.READABLE
tkinter.WRITABLE
tkinter.EXCEPTION

掩码参数中使用的常量。