发布时间:2025-12-09 18:48:48 浏览次数:4
Graphical User Interfaces with Tk — Python 3.11.3 documentation
Tk图形用户界面(GUI) — Python 3.11.3 文档
Tcl/Tk是一种GUI工具包和脚本语言,它们经常一起使用。
Tcl(Tool Command Language)是一种解释性脚本语言,它被设计用于在应用程序中嵌入脚本语言。
Tk是一个跨平台的图形用户界面(GUI)工具包,它与Tcl绑定在一起。Tk提供了大量的GUI组件(如窗口、按钮、标签、文本框等),它们可以通过Tcl脚本语言进行控制。
Tcl/Tk的优点包括:
Tcl/Tk的缺点包括:
tkinter 包是使用面向对象方式对 Tcl/Tk 进行的一层薄包装。 使用 tkinter,你不需要写 Tcl 代码,但你将需要参阅 Tk 文档,有时还需要参阅 Tcl 文档。
tkinter 是一组包装器,它将 Tk 的可视化部件实现为相应的 Python 类。 tkinter 的主要特点是速度很快,并且通常直接附带在 Python 中。 虽然它的官方文档做得不好,但还是有许多可用的资源,包括:在线参考、教程、入门书等等。 tkinter 还有众所周知的较过时的外观界面,这在 Tk 8.5 中已得到很大改进。
总之,Tcl/Tk是一个强大的GUI工具包和脚本语言,它具有跨平台性、易学易用和可扩展性等优点,但可能不如其他GUI工具包在性能和界面美观度方面。
Tcl/Tk 不是只有单个库,而是由几个不同的模块组成的,每个模块都有各自的功能和各自的官方文档。 Python 的二进制发行版还会再附加一个模块。
Tcl
Tcl 是一种动态解释型编程语言,正如 Python 一样。尽管它可作为一种通用的编程语言单独使用,但最常见的用法还是作为脚本引擎或 Tk 工具包的接口嵌入到 C 程序中。Tcl 库有一个 C 接口,用于创建和管理一个或多个 Tcl 解释器实例,并在这些实例中运行 Tcl 命令和脚本,添加用 Tcl 或 C 语言实现的自定义命令。每个解释器都拥有一个事件队列,某些部件可向解释器发送事件交由其处理。与 Python 不同,Tcl 的执行模型是围绕协同多任务而设计的,Tkinter 协调了两者的差别(详见 Threading model )。
Tk
Tk is a Tcl package implemented in C that adds custom commands to create and manipulate GUI widgets. Each Tk object embeds its own Tcl interpreter instance with Tk loaded into it. Tk’s widgets are very customizable, though at the cost of a dated appearance. Tk uses Tcl’s event queue to generate and process GUI events.
Ttk
带有主题的 Tk(Ttk)是较新加入的 Tk 部件,相比很多经典的 Tk 部件,在各平台提供的界面更加美观。自 Tk 8.5 版本开始,Ttk 作为 Tk 的成员进行发布。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 发起调用。
使用示例:
my_dict = create_dict([('a', 1), ('b', 2), ('c', 3)])print(my_dict) # {'a': 1, 'b': 2, 'c': 3}使用示例:
my_list = create_list(1, 2, 3)print(my_list) # [1, 2, 3]type()
构造2个等价的类实例
使用示例:
my_class = create_class('MyClass', (object,), x=1, y=2)print(my_class) # <class '__main__.MyClass'>print(my_class.x) # 1print(my_class.y) # 2这些工厂函数的例子只是Python中工厂函数的冰山一角,工厂函数可以用于创建各种对象,包括实例、函数、模块等等。使用工厂函数可以使代码更加简洁、可读性更高、更易于维护。
TkDocs
关于使用 Tkinter 创建用户界面的详细教程。 讲解了关键概念,并介绍了使用现代 API 的推荐方式。
Tkinter 8.5 参考手册:一种 Python GUI
详细讲解可用的类、方法和选项的 Tkinter 8.5 参考文档。
Tk 命令
有关 Tkinter 所使用的每个底层 Tcl/Tk 命令的完整参考文档。
Tcl/Tk 主页
额外的文档,以及 Tcl/Tk 核心开发相关链接。
Modern Tkinter for Busy Python Developers
Mark Roseman 著。 (ISBN 978-1999149567)
Python and Tkinter Programming
Alan Moore 著。 (ISBN 978-1788835886)
Programming 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 的 “Hello World” 应用程序。 这并不是我们所能写出的最简短版本,但也足够说明你所需要了解的一些关键概念。
在导入语句之后,下一行语句创建了一个 Tk 类的实例,
下一行创建了一个框架控件
下一行创建了一个包含静态文本字符串(Hellow World!)的标签控件(ttk.Lable)。
接下来创建了一个按钮控件,并被放置到标签的右侧。 当被按下时,它将调用 root 窗口的 destroy() 方法。
窗口设计完成.最后,mainloop() 方法将所有控件显示出来,并响应用户输入直到程序终结。
即便是这样简单的程序也阐明了以下关键 Tk 概念:
控件
Tkinter 用户界面是由一个个 控件 组成的。 每个控件都由相应的 Python 对象表示,由 ttk.Frame, ttk.Label 以及 ttk.Button 这样的类来实例化。
控件层级结构
配置选项
控件具有 配置选项,配置选项会改变控件的外观和行为,例如要在标签或按钮中显示的文本。
不同的控件类会具有不同的选项集。
几何管理
事件循环
With your first example behind you, you now have a basic idea of what a Tk program looks like and the type of code you need to write to make it work. In this chapter, we’ll step back and look at three broad concepts that you need to know to understand Tk:
widgets,
geometry management,
and event handling
当你的应用程序使用 Tkinter 的类和方法时,Tkinter 内部汇编代表 Tcl/Tk 命令的字符串,并且在连接到你的应用程序的 Tk 实例的 Tcl 解释器中执行这些命令。
无论是试图浏览参考文档,或是试图找到正确的方法或选项,调整一些现有的代码,亦或是调试 Tkinter 应用程序,有时候理解底层 Tcl/Tk 命令是什么样子的会很有用。
为了说明这一点,下面是 Tcl/Tk 等价于上面 Tkinter 脚本的主要部分。
Tcl 的语法类似于许多 shell 语言,其中第一个单词是要执行的命令,后面是该命令的参数,用空格分隔。不谈太多细节,请注意以下几点:
用于创建窗口小部件(如 ttk::frame)的命令对应于 Tkinter 中的 widget 类。
Tcl 窗口控件选项(如 -text)对应于 Tkinter 中的关键字参数。
在 Tcl 中,小部件是通过 路径名 引用的(例如 .frm.btn),而 Tkinter 不使用名称,而是使用对象引用。
控件在控件层次结构中的位置在其(层次结构)路径名中编码,该路径名使用一个 . (点)作为路径分隔符。
在 Tcl 中以独立的 命令 实现的操作(比如 grid 和 destroy )在 Tkinter 控件对象上以 方法 表示。
稍后您将看到,在其他时候,Tcl 在控件对象调用的方法,在 Tkinter 也有对应的使用。
在Tkinter中,布局管理器(Layout Manager)用于在窗口中放置和组织小部件。Tkinter提供了三种主要的布局管理器:pack()、grid()和place()。
这些布局管理器可以根据需要灵活地混合使用。下面是每个布局管理器的详细说明:
在实际使用中,我们可以根据需要将不同的布局管理器结合起来使用。例如,我们可以使用pack()将一组小部件水平堆叠,然后使用grid()将另一组小部件放置在网格中。
除了这三种布局管理器,Tkinter还提供了Frame小部件,它可以用作容器来组织其他小部件。
以下是一个使用pack布局管理器的简单示例:
import tkinter as tkroot = tk.Tk()label1 = tk.Label(root, text="Label 1", bg="red")label1.pack(side="left")label2 = tk.Label(root, text="Label 2", bg="green")label2.pack(side="left")label3 = tk.Label(root, text="Label 3", bg="blue")label3.pack(side="left")root.mainloop()以下是一个使用grid布局管理器的简单示例:
import tkinter as tkroot = tk.Tk()label1 = tk.Label(root, text="Label 1", bg="red")label1.grid(row=0, column=0)label2 = tk.Label(root, text="Label 2", bg="green")label2.grid(row=0, column=1)label3 = tk.Label(root, text="Label 3", bg="blue")label3.grid(row=1, column=0, columnspan=2)root.mainloop()在这个示例中,我们创建了三个Label小部件,使用grid布局管理器将它们放置在窗口中。我们使用row和column参数指定小部件的行和列,可以使用rowspan和columnspan参数指定小部件的大小。grid布局管理器还提供了其他选项,例如sticky和padx,可以控制小部件在网格中的位置和大小。
place布局管理器是Tkinter中最灵活的布局管理器之一,它允许开发人员使用绝对坐标来放置小部件。place布局管理器使用place()方法将小部件添加到容器中,它提供了一些选项,例如x、y、width和height,可以控制小部件的位置和大小。
以下是一个使用place布局管理器的简单示例:
import tkinter as tkroot = tk.Tk()label1 = tk.Label(root, text="Label 1", bg="red")label1.place(x=50, y=50)label2 = tk.Label(root, text="Label 2", bg="green")label2.place(x=100, y=100)label3 = tk.Label(root, text="Label 3", bg="blue")label3.place(x=150, y=150, width=50, height=50)root.mainloop()在这个示例中,我们创建了三个Label小部件,使用place布局管理器将它们放置在窗口中。我们使用x和y参数指定小部件的位置,可以使用width和height参数指定小部件的大小。place布局管理器还提供了其他选项,例如anchor和relx,可以控制小部件在窗口中的位置和大小。
总之,Tkinter提供了三种常用的布局管理器:pack、grid和place。这些布局管理器可以控制小部件在窗口中的位置和大小。pack布局管理器可以将小部件紧凑地放置在窗口中,grid布局管理器使用网格来组织小部件,place布局管理器允许开发人员使用绝对坐标来放置小部件。根据具体需求选择合适的布局管理器可以帮助开发人员更好地构建用户界面。
要找出控件上可用的配置选项,请调用其 configure() 方法,该方法返回一个字典,其中包含每个对象的各种信息,包括其默认值和当前值。
使用 keys() 获取每个选项的名称。
eg
btn.configure()
{'command': ('command', 'command', 'Command', '', ''),'default': ('default','default','Default',<string object: 'normal'>,<string object: 'normal'>),'takefocus': ('takefocus','takeFocus','TakeFocus','ttk::takefocus','ttk::takefocus'),'text': ('text', 'text', 'Text', '', 'this is a button'),'textvariable': ('textvariable', 'textVariable', 'Variable', '', ''),'underline': ('underline', 'underline', 'Underline', -1, -1),'width': ('width', 'width', 'Width', '', ''),'image': ('image', 'image', 'Image', '', ''),'compound': ('compound', 'compound', 'Compound', '', ''),'padding': ('padding', 'padding', 'Pad', '', ''),'state': ('state','state','State',<string object: 'normal'>,<string object: 'normal'>),'cursor': ('cursor', 'cursor', 'Cursor', '', ''),'style': ('style', 'style', 'Style', '', ''),'class': ('class', '', '', '', '')}As you can see, for each option, Tk will show you the name of theoption and its current value (along with three other attributes whichyou won’t normally need to worry about).
由于大多数控件都有许多共同的配置选项,因此找出特定于特定控件类的配置选项可能会很有用。
将选项列表与更简单的控件(如框架)的列表进行比较是一种方法。
类似地,你可以使用标准函数 dir() 来查找控件对象的可用方法。
如果您尝试一下,您会发现有超过200种常见的控件方法
因此再次确认那些特定于控件类的方法是有帮助的。
In tkinter, an event is an action that occurs in a GUI application, such as clicking a button or pressing a key on the keyboard.
To handle events in tkinter, you need to bind a function or method to an event.
For example, you might bind a button click event to a function that updates a label on the screen. Here’s some sample code that demonstrates this concept:
In this code, we create a Button widget and bind its command parameter to the update_label function. This means that when the button is clicked, the update_label function will be called. The function updates the text of the Label widget to display “Button clicked!”.
In summary, events in tkinter are actions that occur in a GUI application,
binding is the process of associating a function or method with a specific event.
以cavans.bind为例
(method) def bind(sequence: str | None = None,func: ((Event[Canvas]) -> object) | None = None,add: bool | Literal['', '+'] | None = None) -> strBind to this widget at event SEQUENCE a call to function FUNC.
SEQUENCE is a string of concatenated event patterns. An event pattern is of the form <MODIFIER-MODIFIER-TYPE-DETAIL> where
MODIFIER is one of Control, Mod2, M2, Shift, Mod3, M3, Lock, Mod4, M4, Button1, B1, Mod5, M5 Button2, B2, Meta, M, Button3, B3, Alt, Button4, B4, Double, Button5, B5 Triple, Mod1, M1.
TYPE is one of Activate, Enter, Map, ButtonPress, Button, Expose, Motion, ButtonRelease FocusIn, MouseWheel, Circulate, FocusOut, Property, Colormap, Gravity Reparent, Configure, KeyPress, Key, Unmap, Deactivate, KeyRelease Visibility, Destroy, Leave
DETAIL is the button number for ButtonPress, ButtonRelease and DETAIL is the Keysym for KeyPress and KeyRelease.
Examples are for pressing Control and mouse button 1 or for pressing A and the Alt key (KeyPress can be omitted).
An event pattern can also be a virtual event of the form <<AString>> where AString can be arbitrary. This event can be generated by event_generate.
If events are concatenated they must appear shortly after each other.
FUNC will be called if the event sequence occurs with an instance of Event as argument. If the return value of FUNC is “break” no further bound function is invoked.
An additional boolean parameter ADD specifies whether FUNC will be called additionally to the other bound function or whether it will replace the previous function.
Bind will return an identifier to allow deletion of the bound function with unbind without memory leak.
If FUNC or SEQUENCE is omitted the bound function or list of bound events are returned.
The events we’ve seen so far are low-level operating system eventslike mouse clicks and window resizes. Many widgets also generatehigher level or semantic events called virtual events. These areindicated by double angle brackets around the event name, e.g.,<>.For example, a listbox widget will generate a <>virtual event whenever its selection changes.
The same virtual eventis generated whether a user clicked on an item, moved to it using thearrow keys, or some other way. Virtual events avoid the problem ofsetting up multiple, possibly platform-specific event bindings tocapture common changes.
The available virtual events for a widgetwill be listed in the documentation for the widget class.Tk also defines virtual events for common operations that aretriggered in different ways for different platforms. These include<>, <> and <>.
You can define your own virtual events, which can be specific toyour application. This can be a useful way to keep platform-specificdetails isolated in a single module, while you use the virtual eventthroughout your application. Your own code can generate virtualevents that work in exactly the same way that virtual eventsgenerated by Tk do.root.event_generate(“<>”)
tkinter中的Multiple Bindings for an Event:在Tkinter中,可以使用bind方法来将事件绑定到小部件上。
如果您为同一个事件绑定了多个函数,这称为“多个绑定”。
例如,以下代码将鼠标左键单击事件绑定到一个按钮上:
在这个例子中,当单击按钮时,将只会调用func2。
因为func1被后来的绑定func2所屏蔽
如果我们将代码中相应片段修改(使用了add)参数,那么一个事件可以有序触发多个binding(函数)
您可以通过unbind方法来解除绑定,例如:
Tkdocs · GitCode
这部分一些细节先跳过,以后再聊
Tkinter中的sticky参数用于指定Widget在其所在的区域中的对齐方式。它可以应用于pack()、grid()和place()等几种布局管理器中。
sticky参数的取值可以是组合的方向值,如N、S、E、W,也可以是它们的组合,如NE、SW、NW、SE。这些方向值表示Widget在其所在的区域中的对齐方式,如:
如果需要在多个方向上对齐Widget,可以使用它们的组合,例如"NW"表示Widget在区域的左上方对齐。
在使用sticky参数时,可以组合多个方向值,表示Widget在其所在区域中的对齐方式。例如,如果将sticky设置为"NS",则Widget将在其所在区域的上下两侧都对齐。
需要注意的是,当使用grid()布局管理器时,sticky参数只能应用于填充单元格的Widget,而不能应用于使用columnspan或rowspan跨越多个单元格的Widget。
例如,sticky参数被设置为(W, E),这意味着小部件将被左对齐和右对齐。具体来说,这意味着小部件将完全填充其单元格,并将其左边缘对齐网格的左边缘,同时将其右边缘对齐网格的右边缘。
这通常用于将小部件放置在窗口的底部,并使其水平居中对齐。
下面是一个示例代码,演示了grid()方法中sticky参数的使用:
import tkinter as tkroot = tk.Tk()root.geometry("200x100")label = tk.Label(root, text="Hello, World!")label.grid(row=0, column=0, sticky=(tk.W, tk.E))root.mainloop()在这个例子中,我们创建了一个Label小部件,并将其放置在网格的第一行第一列。
sticky参数被设置为(W, E),以便使标签左对齐和右对齐。这使得标签在窗口中水平居中对齐
下面是一个简单的例子,可以让你体验sticky参数的效果。这个例子使用grid()布局管理器,将三个Button Widget放在一个Frame Widget中,并使用sticky参数来指定它们的对齐方式。
import tkinter as tkroot = tk.Tk()frame = tk.Frame(root, bg="gray", padx=10, pady=10)frame.grid(row=0, column=0, sticky="NESW")btn1 = tk.Button(frame, text="Button 1")btn1.grid(row=0, column=0, sticky="W")btn2 = tk.Button(frame, text="Button 2")btn2.grid(row=1, column=0, sticky="E")btn3 = tk.Button(frame, text="Button 3")btn3.grid(row=0, column=1, rowspan=2, sticky="NS")root.mainloop()在上面的例子中,我们创建了一个Frame Widget,并将其放置在主窗口的第一行第一列。然后我们在Frame Widget中添加了三个Button Widget,分别是Button 1、Button 2和Button 3。
使用sticky参数,我们指定了Button 1在其所在的区域的左侧对齐,Button 2在其所在的区域的右侧对齐,Button 3在其所在的区域的上下两侧都对齐。最终的效果如下图所示:
从上面的例子中可以看出,使用sticky参数可以方便地对Widget进行对齐,使得布局更加美观和易读。
下面是一个稍微改动了一下sticky参数的例子,可以让你更清楚地看出不同参数的效果。在这个例子中,我们将三个Button Widget放在一个Frame Widget中,并使用不同的sticky参数来指定它们的对齐方式。
import tkinter as tkroot = tk.Tk()frame = tk.Frame(root, bg="gray", padx=10, pady=10)frame.grid(row=0, column=0)btn1 = tk.Button(frame, text="Button 1")btn1.grid(row=0, column=0, sticky="W")btn2 = tk.Button(frame, text="Button 2")btn2.grid(row=1, column=0, sticky="E")btn3 = tk.Button(frame, text="Button 3")btn3.grid(row=0, column=1, rowspan=2, sticky="NS")root.mainloop()例如,将Button 1的sticky参数设置为"WE",可以让它在水平方向上占据整个区域;将Button 2的sticky参数设置为"NS",可以让它在垂直方向上占据整个区域。你还可以尝试组合不同的方向值来看看效果的变化。