tkinter — Python 的 Tcl/Tk 接口

源代码: Lib/tkinter/__init__.py


tkinter 包(“Tk 接口”)是 Python 对 Tcl/Tk GUI 工具包的标准接口。Tk 和 tkinter 在大多数 Unix 平台(包括 macOS)以及 Windows 系统上都可用。

从命令行运行 python -m tkinter 应该会打开一个演示简单 Tk 界面的窗口,让你知道 tkinter 已在你的系统上正确安装,并显示已安装的 Tcl/Tk 版本,以便你可以阅读该版本对应的 Tcl/Tk 文档。

Tkinter 支持一系列 Tcl/Tk 版本,无论是否带有线程支持。Python 官方二进制发行版捆绑了 Tcl/Tk 8.6 线程版。有关支持版本的更多信息,请参阅 _tkinter 模块的源代码。

Tkinter 不是一个薄封装层,而是增加了相当多的自有逻辑,以使体验更符合 Python 风格。本文档将重点介绍这些增补和改动,对于未变动的细节,将引述官方 Tcl/Tk 文档。

备注

Tcl/Tk 8.5(2007年)引入了一套现代化的主题用户界面组件以及使用它们的新 API。新旧 API 仍然可用。你在网上找到的大多数文档仍然使用旧 API,可能已经严重过时。

参见

Tcl/Tk 资源

  • Tk 命令

    Tkinter 所使用的每个底层 Tcl/Tk 命令的综合参考。

  • Tcl/Tk 主页

    附加文档,以及 Tcl/Tk 核心开发的链接。

书籍

架构

Tcl/Tk 不是单一的库,而是由几个不同的模块组成,每个模块都有独立的功能和自己的官方文档。Python 的二进制发行版也附带了一个附加模块。

Tcl

Tcl 是一种动态解释型编程语言,就像 Python 一样。虽然它可以作为通用编程语言单独使用,但它最常被嵌入到 C 应用程序中,作为脚本引擎或 Tk 工具包的接口。Tcl 库有一个 C 接口,用于创建和管理一个或多个 Tcl 解释器实例,在这些实例中运行 Tcl 命令和脚本,并添加用 Tcl 或 C 实现的自定义命令。每个解释器都有一个事件队列,并且有设施可以向其发送事件并处理它们。与 Python 不同,Tcl 的执行模型是围绕协作式多任务设计的,Tkinter 弥合了这一差异(详见线程模型)。

Tk

Tk 是一个用 C 实现的 Tcl 包,它添加了用于创建和操作 GUI 部件的自定义命令。每个 Tk 对象都内嵌了自己加载了 Tk 的 Tcl 解释器实例。Tk 的部件具有高度可定制性,但代价是外观略显陈旧。Tk 使用 Tcl 的事件队列来生成和处理 GUI 事件。

Ttk

主题化 Tk (Ttk) 是一个较新的 Tk 部件系列,相比许多经典的 Tk 部件,它在不同平台上提供了更好的外观。Ttk 作为 Tk 的一部分分发,从 Tk 8.5 版本开始。Python 绑定在单独的模块 tkinter.ttk 中提供。

在内部,Tk 和 Ttk 使用底层操作系统的设施,即 Unix/X11 上的 Xlib、macOS 上的 Cocoa、Windows 上的 GDI。

当你的 Python 应用程序使用 Tkinter 中的一个类(例如,创建一个部件)时,tkinter 模块首先会组装一个 Tcl/Tk 命令字符串。它将该 Tcl 命令字符串传递给一个内部的 _tkinter 二进制模块,该模块再调用 Tcl 解释器来执行它。Tcl 解释器接着会调用 Tk 和/或 Ttk 包,这些包又会调用 Xlib、Cocoa 或 GDI。

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

tk

通过实例化 Tk 创建的 Tk 应用程序对象。它提供了对 Tcl 解释器的访问。附加到同一个 Tk 实例的每个部件的 tk 属性都具有相同的值。

master

包含此部件的部件对象。对于 TkmasterNone,因为它是主窗口。术语 masterparent 类似,有时作为参数名互换使用;但是,调用 winfo_parent() 返回部件名称的字符串,而 master 返回对象。parent/child 反映了树状关系,而 master/slave 反映了容器结构。

children

此部件的直接后代,以一个 dict 形式表示,其中子部件名称为键,子实例对象为值。

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

Tcl() 函数是一个工厂函数,它创建一个与 Tk 类创建的对象非常相似的对象,但它不初始化 Tk 子系统。这在驱动 Tcl 解释器而不想创建多余的顶层窗口的环境中,或者在无法创建(例如没有 X 服务器的 Unix/Linux 系统)的环境中,通常最有用。通过调用其 loadtk() 方法,可以为由 Tcl() 对象创建的对象创建一个 Toplevel 窗口(并初始化 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 解释器静态链接。

idlelib

Python 的集成开发和学习环境 (IDLE)。基于 tkinter

tkinter.constants

在向 Tkinter 调用传递各种参数时,可以用作字符串替代的符号常量。由主 tkinter 模块自动导入。

tkinter.dnd

(实验性)tkinter 的拖放支持。当被 Tk DND 替换时,它将被弃用。

turtle

Tk 窗口中的海龟绘图。

Tkinter 救生筏

本节不旨在成为 Tk 或 Tkinter 的详尽教程。为此,请参考前面提到的外部资源之一。相反,本节提供了一个关于 Tkinter 应用程序外观的非常快速的介绍,确定了基本的 Tk 概念,并解释了 Tkinter 封装层的结构。

本节的其余部分将帮助你识别 Tkinter 应用程序中所需的类、方法和选项,以及在哪里可以找到关于它们的更详细的文档,包括在官方的 Tcl/Tk 参考手册中。

一个 Hello World 程序

我们将从一个 Tkinter 的 "Hello World" 应用程序开始。这并非我们能写出的最小巧的程序,但它足以说明一些你需要知道的关键概念。

from tkinter import *
from tkinter import ttk
root = Tk()
frm = ttk.Frame(root, padding=10)
frm.grid()
ttk.Label(frm, text="Hello World!").grid(column=0, row=0)
ttk.Button(frm, text="Quit", command=root.destroy).grid(column=1, row=0)
root.mainloop()

在导入之后,下一行创建了一个 Tk 类的实例,它会初始化 Tk 并创建其关联的 Tcl 解释器。它还会创建一个顶层窗口,称为根窗口,作为应用程序的主窗口。

下面这行创建了一个框架(frame)部件,在本例中它将包含我们接下来要创建的一个标签和一个按钮。该框架被放置在根窗口内。

下一行创建了一个包含静态文本字符串的标签部件。grid() 方法用于指定标签在其包含的框架部件中的相对布局(位置),类似于 HTML 中的表格工作方式。

接着创建了一个按钮部件,并放置在标签的右侧。当按下时,它将调用根窗口的 destroy() 方法。

最后,mainloop() 方法将所有内容显示在屏幕上,并响应用户输入,直到程序终止。

重要的 Tk 概念

即使是这个简单的程序也阐释了以下关键的 Tk 概念:

部件 (widgets)

一个 Tkinter 用户界面由单个的 *部件* 组成。每个部件都表示为一个 Python 对象,从诸如 ttk.Framettk.Labelttk.Button 这样的类实例化。

部件层级 (widget hierarchy)

部件以*层级结构*排列。标签和按钮包含在一个框架中,该框架又包含在根窗口中。在创建每个*子*部件时,其*父*部件作为第一个参数传递给部件构造函数。

配置选项 (configuration options)

部件具有*配置选项*,用于修改其外观和行为,例如标签或按钮中要显示的文本。不同类别的部件将有不同的选项集。

几何管理器 (geometry management)

部件在创建时不会自动添加到用户界面。像 grid 这样的*几何管理器*控制它们在用户界面中的放置位置。

事件循环 (event loop)

Tkinter 只有在主动运行 *事件循环* 时,才会对用户输入、程序更改甚至刷新显示作出反应。如果你的程序没有运行事件循环,你的用户界面将不会更新。

理解 Tkinter 如何封装 Tcl/Tk

当你的应用程序使用 Tkinter 的类和方法时,Tkinter 内部正在组装表示 Tcl/Tk 命令的字符串,并在附加到你应用程序的 Tk 实例的 Tcl 解释器中执行这些命令。

无论是在查阅参考文档、试图找到正确的方法或选项、调整一些现有代码,还是调试你的 Tkinter 应用程序,有时理解那些底层的 Tcl/Tk 命令长什么样会很有用。

为了说明这一点,这里是上面 Tkinter 脚本主要部分的 Tcl/Tk 等价物。

ttk::frame .frm -padding 10
grid .frm
grid [ttk::label .frm.lbl -text "Hello World!"] -column 0 -row 0
grid [ttk::button .frm.btn -text "Quit" -command "destroy ."] -column 1 -row 0

Tcl 的语法类似于许多 shell 语言,其中第一个词是要执行的命令,后面跟着该命令的参数,用空格分隔。不深入太多细节,请注意以下几点:

  • 用于创建部件的命令(如 ttk::frame)对应于 Tkinter 中的部件类。

  • Tcl 部件选项(如 -text)对应于 Tkinter 中的关键字参数。

  • 部件在 Tcl 中通过*路径名*(如 .frm.btn)引用,而 Tkinter 不使用名称,而是使用对象引用。

  • 一个部件在部件层级中的位置被编码在其(层级)路径名中,该路径名使用 .(点)作为路径分隔符。根窗口的路径名就是 .(点)。在 Tkinter 中,层级不是通过路径名定义的,而是在创建每个子部件时指定父部件。

  • 在 Tcl 中作为独立*命令*实现的操作(如 griddestroy)在 Tkinter 中表示为部件对象的*方法*。正如你很快会看到的,在其他时候,Tcl 使用的看起来像是对部件对象的方法调用,这更接近于 Tkinter 中的用法。

我该如何……?哪个选项可以……?

如果你不确定如何在 Tkinter 中做某件事,并且在你正在使用的教程或参考文档中找不到它,有几种策略可能会有帮助。

首先,请记住,单个部件的工作细节可能因 Tkinter 和 Tcl/Tk 的不同版本而异。如果你正在搜索文档,请确保它与你系统上安装的 Python 和 Tcl/Tk 版本相对应。

在搜索如何使用 API 时,知道你正在使用的类、选项或方法的确切名称会很有帮助。在交互式 Python shell 中或使用 print() 进行内省可以帮助你识别所需的内容。

要了解任何部件上有哪些配置选项,可以调用其 configure() 方法,它会返回一个字典,其中包含关于每个对象的各种信息,包括其默认值和当前值。使用 keys() 只获取每个选项的名称。

btn = ttk.Button(frm, ...)
print(btn.configure().keys())

由于大多数部件有许多共同的配置选项,找出哪些是特定于某个部件类的选项可能会很有用。将选项列表与像框架这样更简单的部件的选项列表进行比较是一种方法。

print(set(btn.configure().keys()) - set(frm.configure().keys()))

同样,你可以使用标准的 dir() 函数找到部件对象的可用方法。如果你尝试一下,你会发现有超过 200 个常见的部件方法,因此识别特定于某个部件类的方法会很有帮助。

print(dir(btn))
print(set(dir(btn)) - set(dir(frm)))

线程模型

Python 和 Tcl/Tk 有非常不同的线程模型,tkinter 试图弥合这一差异。如果你使用线程,你可能需要注意这一点。

一个 Python 解释器可以关联多个线程。在 Tcl 中,可以创建多个线程,但每个线程都关联一个独立的 Tcl 解释器实例。线程也可以创建多个解释器实例,但每个解释器实例只能由创建它的那个线程使用。

每个由 tkinter 创建的 Tk 对象都包含一个 Tcl 解释器。它还跟踪是哪个线程创建了该解释器。对 tkinter 的调用可以从任何 Python 线程进行。在内部,如果一个调用来自创建 Tk 对象的线程以外的线程,一个事件会被发布到解释器的事件队列中,当执行时,结果会返回给调用它的 Python 线程。

Tcl/Tk 应用程序通常是事件驱动的,这意味着在初始化之后,解释器会运行一个事件循环(即 Tk.mainloop())并响应事件。因为它是单线程的,所以事件处理器必须快速响应,否则它们会阻塞其他事件的处理。为避免这种情况,任何长时间运行的计算都不应在事件处理器中运行,而是要么使用定时器分解成更小的部分,要么在另一个线程中运行。这与许多 GUI 工具包不同,在这些工具包中,GUI 在一个与所有应用程序代码(包括事件处理器)完全独立的线程中运行。

如果 Tcl 解释器没有运行事件循环并处理事件,那么从运行 Tcl 解释器的线程以外的线程进行的任何 tkinter 调用都会失败。

存在一些特殊情况:

  • Tcl/Tk 库可以被构建为非线程安全的。在这种情况下,tkinter 会从发起调用的 Python 线程中调用该库,即使这个线程与创建 Tcl 解释器的线程不同。一个全局锁确保一次只有一个调用发生。

  • 虽然 tkinter 允许你创建多个 Tk 对象实例(每个都有自己的解释器),但同一线程中的所有解释器共享一个公共事件队列,这很快就会变得混乱。实际上,不要一次创建多个 Tk 实例。否则,最好在不同的线程中创建它们,并确保你正在运行一个支持线程的 Tcl/Tk 构建版本。

  • 阻塞事件处理器不是阻止 Tcl 解释器重新进入事件循环的唯一方法。甚至可以运行多个嵌套的事件循环或完全放弃事件循环。如果你在事件或线程方面做任何棘手的事情,请注意这些可能性。

  • 目前有少数几个 tkinter 函数只有在创建 Tcl 解释器的线程中调用时才能工作。

便捷参考

设置选项

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

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

要完整了解给定选项及其行为,请参阅相关部件的 Tk 手册页。

请注意,手册页为每个部件列出了“标准选项”和“部件特定选项”。前者是许多部件共有的选项列表,后者是该特定部件特有的选项。“标准选项”记录在 options(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')}

当然,打印出的字典将包含所有可用选项及其值。这只是一个示例。

Packer(布局管理器)

packer 是 Tk 的几何管理机制之一。几何管理器用于指定部件在其容器(它们的共同*master*)内的相对位置。与更繁琐的 *placer*(使用较少,我们在此不作介绍)相比,packer 采用定性关系规范——*上方*、*左侧*、*填充*等——并为你计算出确切的放置坐标。

任何 *master* 部件的大小由其内部的“slave widgets”的大小决定。packer 用于控制 slave 部件在它们被打包进去的 master 内部出现的位置。你可以将部件打包到框架中,再将框架打包到其他框架中,以实现你想要的布局。此外,一旦打包,布局会动态调整以适应配置的增量变化。

请注意,除非用几何管理器指定了部件的几何形状,否则部件不会出现。一个常见的早期错误是忘记了几何规范,然后惊讶于部件已创建但什么也没出现。一个部件只有在应用了例如 packer 的 pack() 方法之后才会出现。

pack() 方法可以与关键字-选项/值对一起调用,这些对控制部件在其容器中出现的位置,以及当主应用程序窗口调整大小时它的行为方式。以下是一些示例:

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

Packer 选项

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

anchor

锚点类型。表示 packer 将每个 slave 放置在其区域中的位置。

expand

布尔值,01

fill

合法值为:'x''y''both''none'

ipadx 和 ipady

一个距离 - 指定 slave 部件每侧的内部填充。

padx 和 pady

一个距离 - 指定 slave 部件每侧的外部填充。

side

合法值为:'left''right''top''bottom'

耦合部件变量

某些部件(如文本输入部件)的当前值设置可以通过使用特殊选项直接连接到应用程序变量。这些选项是 variabletextvariableonvalueoffvaluevalue。这种连接是双向的:如果变量因任何原因发生变化,与之连接的部件将被更新以反映新值。

不幸的是,在 tkinter 的当前实现中,无法通过 variabletextvariable 选项将任意 Python 变量传递给部件。唯一能实现此功能的变量类型是那些从 tkinter 中定义的名为 Variable 的类继承的子类变量。

已经定义了许多有用的 Variable 子类:StringVarIntVarDoubleVarBooleanVar。要读取这类变量的当前值,请在其上调用 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 的方法。

要访问包含给定部件的顶层窗口,你通常可以直接引用该部件的 master。当然,如果该部件被打包在一个框架内,master 将不代表一个顶层窗口。要访问包含任意部件的顶层窗口,你可以调用 _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()

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"

回调

这是任何不带参数的 Python 函数。例如:

def print_it():
    print("hi there")
fred["command"] = print_it
color

颜色可以以 rgb.txt 文件中的 X 颜色名称给出,也可以是表示 RGB 值的字符串,格式有 4 位:"#RGB",8 位:"#RRGGBB",12 位:"#RRRGGGBBB",或 16 位:"#RRRRGGGGBBBB",其中 R、G、B 代表任何合法的十六进制数字。详情请见 Ousterhout 书的第 160 页。

cursor

可以使用 cursorfont.h 中的标准 X 光标名称,无需 XC_ 前缀。例如,要获得手形光标(XC_hand2),请使用字符串 "hand2"。你也可以指定自己的位图和掩码文件。请参阅 Ousterhout 书的第 179 页。

distance

屏幕距离可以以像素或绝对距离指定。像素以数字给出,绝对距离以字符串给出,尾随字符表示单位:c 表示厘米,i 表示英寸,m 表示毫米,p 表示印刷点。例如,3.5 英寸表示为 "3.5i"

font

Tk 使用列表字体名称格式,例如 {courier 10 bold}。正数大小的字体以点为单位测量;负数大小的字体以像素为单位测量。

geometry

这是一个形如 widthxheight 的字符串,其中 width 和 height 对于大多数部件是以像素为单位测量的(对于显示文本的部件是以字符为单位)。例如: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() 方法,但也可以是任何接受单个参数的部件方法。

wrap

必须是以下之一:"none""char""word"

绑定和事件

来自部件命令的 bind 方法允许你监视某些事件,并在该事件类型发生时触发一个回调函数。bind 方法的形式是:

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

其中:

序列

是一个表示目标事件类型的字符串。(详见 bind(3tk) 手册页和 John Ousterhout 的书《Tcl and the Tk Toolkit (2nd edition)》的第 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.invoke(), menu.entryconfig() 等)

菜单的一些选项和方法操作特定的菜单条目。任何时候需要为选项或参数提供菜单索引时,你都可以传递:

  • 一个整数,表示条目在部件中的数字位置,从顶部开始计数,从 0 开始;

  • 字符串 "active",它指的是当前在光标下的菜单位置;

  • 字符串 "last",它指的是最后一个菜单项;

  • 一个以 @ 开头的整数,如 @6,其中整数被解释为菜单坐标系中的 y 像素坐标;

  • 字符串 "none",表示根本没有菜单条目,最常用于 menu.activate() 以取消所有条目的激活状态,最后,

  • 一个文本字符串,从菜单顶部到底部扫描,与菜单条目的标签进行模式匹配。请注意,此索引类型在所有其他索引类型之后考虑,这意味着标记为 lastactivenone 的菜单项的匹配可能会被解释为上述字面值。

图像

不同格式的图像可以通过 tkinter.Image 的相应子类创建:

  • BitmapImage 用于 XBM 格式的图像。

  • PhotoImage 用于 PGM、PPM、GIF 和 PNG 格式的图像。后者从 Tk 8.6 开始支持。

任何一种类型的图像都是通过 filedata 选项创建的(也提供其他选项)。

在 3.13 版更改: 增加了 PhotoImagecopy_replace() 方法,用于将一个图像的区域复制到另一个图像,可能带有像素缩放和/或子采样。向 PhotoImagecopy()zoom()subsample() 方法添加 from_coords 参数。向 PhotoImagecopy() 方法添加 zoomsubsample 参数。

然后,图像对象可以在任何支持 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 上不可用。

由于你不知道有多少字节可供读取,你可能不想使用 BufferedIOBaseTextIOBaseread()readline() 方法,因为这些方法会坚持读取预定义数量的字节。对于套接字,recv()recvfrom() 方法可以正常工作;对于其他文件,请使用原始读取或 os.read(file.fileno(), maxbytecount)

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

注册文件处理器回调函数 funcfile 参数可以是一个具有 fileno() 方法的对象(例如文件或套接字对象),也可以是一个整数文件描述符。mask 参数是下面三个常量中任意一个的“或”组合。回调函数按以下方式调用:

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

注销一个文件处理器。

_tkinter.READABLE
_tkinter.WRITABLE
_tkinter.EXCEPTION

在 *mask* 参数中使用的常量。