参考资源:
- TKDocs:大量的教程,部分可视化组件的介绍说明
Python3.7 已经自动集成了 tkinter,无需安装。
Tk 程序有 3 个基础概念:部件(widgets)、几何管理(geometry management)、事件处理(event handling)。下面逐一介绍。
1 Widgets
widgets (有时也称为 controls(控件)或者 windows(窗口))指代您在屏幕上看到的对象,包含有 button,entry,labels,frame,checkboxes,tree views,scrollbars,text areas 等等。
1.1 窗口具有层次结构
在 Tk 中所有的 widgets 都是一个单根(root,即最顶层的 widget)的具有层次结构的窗口(Window Hierarchy)。当我们创建一个 widget 时必须传入它的父节点。比如:
from tkinter import ttk
from tkinter import Tk
root = Tk() # 实例化顶层 widget
content = ttk.Frame(root)
button = ttk.Button(content)
可以使用 str(widget)
获取该 widget 的层级结构(有点类似于文件的路径):
str(root), str(content), str(button)
显示结果为:
('.', '.!frame', '.!frame.!button')
可以看出 root 是最顶层的,其次是 content,最后是 button。
1.2 配置选项
所有的 widgets 均有一些配置选项(configuration options),这些选项控制着 widgets 的行为(即如何表现事件的)和状态(即如何被展示的)。下面举例说明:
root = Tk() # 创建顶层 widget
# 向一个 button 传入两个配置选项
button = ttk.Button(root, text='您好', command='buttonpressed')
可以直接使用索引的方式获取配置信息:
button['text']
显示结果为:
'您好'
也可以修改配置信息:
button['text'] = '再见' # 等价于 button.configure(text='再见')
如果需要获取 'text' 的配置信息,可以:
button.configure('text')
('text', 'text', 'Text', '', '再见')
如果需要获取全部的配置信息,可以运行 button.configure()
命令。一些常用的 widgets:frames, labels, buttons, checkbuttons, radiobuttons, entries and comboboxes。您也可以使用 dict(button)
获取 button
的所有属性信息。即:
{'command': 'buttonpressed',
'default': <index object: 'normal'>,
'takefocus': 'ttk::takefocus',
'text': '再见',
'textvariable': '',
'underline': -1,
'width': '',
'image': '',
'compound': <index object: 'none'>,
'padding': '',
'state': <index object: 'normal'>,
'cursor': '',
'style': '',
'class': ''}
2 Geometry Management
创建了 widgets 并不能让其直接在屏幕上显示,这是因为还缺少一个关键的步骤:Geometry Management(几何管理)。最常用的就是 grid
几何管理器。
几何管理器依赖于主部件和从部件(master and slave widgets)的概念设定。母版(master)是一个小部件,它通常是顶层窗口(toplevel window)或框架(frame),其中包含了其他小部件,这些小部件被称为从属项(slaves)。您可以将几何管理器当作是在主部件的控制下,决定着在窗口显示着些什么内容。
几何管理器将会询问每个从属部件的自然大小,或者它理想情况下希望显示的大小。然后,当它要求几何管理器管理该特定的从属部件时,它会获取其信息并将其与程序提供的任何参数相结合。
几何管理器获取有关从属的所有信息,以及有关主部件大小的信息,并使用其内部算法确定每个从属部件将分配的区域。每当主参数的大小发生变化(例如,因为顶层窗口被调整大小)、从属窗口的自然大小变化(例如,因为我们已经更改了标签中的文本)或任何几何管理器参数更改(例如,如"row",,"column",或者 "sticky")。
3 Event Handling
在 Tk 中,与大多数其他用户界面工具包一样,有一个事件循环(event loop),从操作系统接收事件。这些事件有按钮按下、击键、鼠标移动、窗口调整大小等。
通常,Tk 会负责为您管理这些事件循环。它将找出事件应用于哪个小部件(用户是否单击此按钮?如果按下了某个键,哪个文本框具有焦点?),并相应地调度它。单个小部件知道如何响应事件;例如,当鼠标移动时,按钮可能会更改颜色,并在鼠标离开时恢复。
3.1 命令回调(Command Callbacks)
通常,尽管您希望程序处理特定事件,例如按下按钮时执行某些操作。对于自定义非常必要的事件(按下按钮时不发生某些内容,该按钮有什么好?),小部件将提供一个回调作为小部件配置选项(widget configuration option)。比如配置选项的 "command"
参数。
Tk 中的回调往往比用于编译语言的工具包中简单(其中回调通常必须针对具有特定参数集的过程或具有特定签名的对象方法)。相反,回调只是解释器执行的正常代码。
3.2 事件绑定
对于没有与其关联的命令回调的事件,可以使用 Tk 的 "bind"
捕获任何事件,然后(与回调类似)执行任意代码段。下面看一个简单的例子,它显示了标签如何设置绑定以响应不同的事件,而只需更改标签中显示的内容即可:
root = Tk()
l = ttk.Label(root, text="Starting...")
l.grid()
l.bind('<Enter>', lambda e: l.configure(text='Moved mouse inside'))
l.bind('<Leave>', lambda e: l.configure(text='Moved mouse outside'))
l.bind('<1>', lambda e: l.configure(text='Clicked left mouse button'))
l.bind('<Double-1>', lambda e: l.configure(text='Double clicked'))
l.bind('<B3-Motion>', lambda e: l.configure(text='right button drag to %d,%d' % (e.x, e.y)))
root.mainloop()
tkinter 希望您将函数作为事件回调,其第一个参数是表示触发回调的事件的事件对象(格式为 <modifier-type-detail>
)。
-
type
:是 event 的核心,通常用于描述事件的类型,比如点击鼠标 -
modifier
:event 的可选部分,通常用于描述事件的组合键,例如Ctrl + S
-
detail
:event 的可选部分,通常用于描述事件的具体按键,例如Button-3
表示鼠标右键
下面简单介绍几个事件:
事件 | 描述 |
---|---|
<Button-1> |
鼠标事件,1 代表左键,可简写为 <1>
|
<Button-2> |
鼠标事件,2 代表中键,可简写为 <2>
|
<Button-3> |
鼠标事件,3 代表右键,可简写为 <3>
|
<Button-4> |
鼠标事件,4 代表鼠标滚轮上滚 |
<Button-5> |
鼠标事件,5 代表鼠标滚轮下滚 |
<B1-Motion> |
鼠标拖动事件,1 代表左键拖动,还有 2, 3 分别代表中键拖动,右键拖动 |
<ButtonRelease-1> |
鼠标按下后释放 |
<Double-Button-1> |
双击鼠标左键 |
<Enter> |
表示鼠标指针进入到 widget 里面 |
<Leave> |
表示鼠标指针离开 widget |
<KeyPress-D> |
用户点击按键 D |
<Control-Shift-KeyPress-Y> |
用户点击组合键 Ctrl + Shift + Y |
事件对象的属性:
属性 | 描述 |
---|---|
widget | 产生的事件的组件 |
x, y | 当前的鼠标相对于窗口的位置,单位:像素 |
x_root, y_root | 当前的鼠标相对于电脑显示屏左上角的位置,单位:像素 |
char | 仅键盘事件支持,表示按键对应的字符 |
num | 按钮数字,仅支持鼠标事件 |
width, height | widget 的大小 |
type | 事件类型 |
对于所有不同的事件名称、修饰符和每个事件参数的完整描述,最好查看的是"绑定"命令引用。
bind
还有两个变体:
-
bind_all
:参数同bind
,作用是绑定到全局 -
bind_class
:有 3 个参数,即(类名, 事件类型, 对应的操作)
,比如:
app.bind_class('ttk.Entry', '<Control-C>', my_copy)
绑定了所有的输入文本框的Ctrl + C
表示复制
3.3 虚拟事件
除了低级操作系统事件(如鼠标单击和窗口调整大小)之外,许多小部件还生成称为虚拟事件(Virtual Events)的更高级别事件。例如,列表框小部件("ListboxSelect")将在选择更改时生成虚拟事件,无论这是因为用户单击了某个项目,还是使用箭头键移动到它等等。这样可以避免设置多个(可能是特定平台的事件绑定)来捕获更改的问题。
3.4 多重绑定
实际上,小部件可以针对单个事件触发(trigger)多个不同的事件绑定。通常,可以为以下设置事件:单个小部件本身、特定类的所有小部件(例如按钮)、包含小部件的顶级窗口以及应用程序中的所有小部件。每一个将依次触发。
当我们在顶层窗口中为 Return 键设置绑定时,我们在示例中看到了这一点,该绑定应用于该窗口中的每个小部件。
Tk 中每个小部件类的默认行为本身是使用脚本级事件绑定定义的,因此可以进行内省和修改,以更改特定类的所有小部件的行为。您甚至可以完全修改每个小部件的多个事件序列的处理;如果您好奇,请参阅"绑定标记"命令引用。