今天我们来讲讲 事件绑定。正如我们此前所提到的,一个 tkinter 的应用程序大部分时间是花费在事件循环中的,也就是通过 mainloop() 方法进入时间循环了,事件可以有各种各样的来源,比如说 用户移动、点击一下鼠标,会产生对应的鼠标事件,在键盘上一个敲击,会产生对应的按键事件,拖动或者改变应用程序的大小,窗口管理器也会触发相应的重绘事件啦。
tkinter 提供一个非常强大的机制可以让你自由的去管理这些事件,定义这些事件的操作,对每一个组件来说,你可以通过 bind() 方法将自己定义的函数或者方法绑定到具体的事件上,我们在此之前已经演示过很多次啦,当被触发的事件满足该组件绑定的事件的时候,tkinter 就会带着事件本身的描述去调用自定义的方法了,我们这里有几个例子给大家感受一下。
第一个是关于鼠标按键的演示:
我们创建一个框架 frame ,然后在这个框架里响应事件就可以了,宽度、高度均为200,<Button-1>,中间有一个小横杠,左边是事件本身,右边是事件的描述,Button 表示鼠标的点击事件,1 表示鼠标左键(2:中间键;3:右键;4和5是对于Linix 系统才有用,对应滚轮的上滚和下滚),我们对这个事件绑定一个自定义的方法:callback(),我们说,当触发 Button-1 这个事件(即点击鼠标左键)的时候,tkinter 会带着事件本身去调用 callback() 方法,它就把这个事件传到这个方法的参数里面,我们这里就需要一个形参来获取,这里命名为 event,用其他名字也一样,event 形参来获取对应的事件描述,我们就简单的把点击那一刻鼠标的位置打印出来,event.x和event.y,这里的x,y 表示的是相对于应用程序左上角的相对位置,还有一个 root.x 和 root.y,是相对于屏幕的位置。我们下面介绍。
-
# 捕获点击鼠标的位置 -
import tkinter as tk -
root = tk.Tk() -
def callback(event): -
print("点击位置:", event.x, event.y) -
frame = tk.Frame(root, width = 200, height = 200) -
frame.bind("<Button-1>", callback) -
frame.pack() -
root.mainloop()

运行结果也表明了:越接近左上角越接近于0。
第二个是关于键盘按键的演示:
键盘相应的是 Key,也可以是 KeyPress(键盘按下),其实,有按下就有释放的过程,像刚才的 Button,也有ButtonRelease,这里总之响应一个 Key 就可以了,关于键盘的事件,有一个特别的要求,就是说,你这个组件想要响应键盘事件,因为一个窗口可能会有很多组件,键盘一次敲击,也不知道给哪个组件,所以他有一个要求,就是你这个组件必须获得焦点,它才会响应键盘来的消息,那怎么获取焦点呢?我们可以设置 Frame 的 takefocus 选项为 True,然后运行时使用 Tab 将焦点转移上来。这里有一个更便捷的方法:用 focus_set() 获得焦点。键盘有一个 char 属性,就是你刚才按下的字符。
-
# 捕获键盘事件 -
import tkinter as tk -
root = tk.Tk() -
def callback(event): -
print("点击的键盘字符为:", event.char) -
frame = tk.Frame(root, width = 200, height = 200) -
frame.bind("<Key>", callback) -
frame.focus_set() -
frame.pack() -
root.mainloop()

但是上面的例子中,当我们点击 ALT、Ctrl、Shift 这一类特殊按键时,就不会显示,但是可以通过 把 event.char 改为 event.keysym 或者 event.keycode 来得到对应按键的 keysym 和 keycode(参照下面的Key names小节)
最后我们再用一个例子展示捕获鼠标在组件上的运动轨迹,这里需要关注的是 <Motion> 事件:
-
# 捕获鼠标在组件上的运动轨迹 -
import tkinter as tk -
root = tk.Tk() -
def callback(event): -
print("当前位置为:", event.x, event.y) -
frame = tk.Frame(root, width = 200, height = 200) -
frame.bind("<Motion>", callback) -
frame.pack() -
root.mainloop()
截止目前为止,我们都是泛泛的跟大家说怎么用,现在我们主要谈一下语法性的东西啦,首先,我们刚才的Button、Key、KeyPress、Motion 都称之为 时间序列。
Tkinter 使用一种称为事件序列的机制来允许用户定义事件,用户需使用 bind() 方法将具体的事件序列与自定义的方法相绑定。事件序列是以字符串的形式表示的,可以表示一个或多个相关联的事件(如果是多个事件,那么对应的方法只有在满足所有事件的前提下才会被调用)。
事件序列使用以下语法描述:
<modifier-type-detail>
- 事件序列是包含在尖括号(<...>)中
- type 部分的内容是最重要的,它通常用于描述普通的事件类型,例如鼠标点击或键盘按键点击(详见下方)。
- modifier 部分的内容是可选的,它通常用于描述组合键,例如 Ctrl + c,Shift + 鼠标左键点击(详见下方)。
- detail 部分的内容是可选的,它通常用于描述具体的按键,例如 Button-1 表示鼠标左键。
举几个例子帮助大家消化:
| 事件序列 | 含义 |
| <Button-1> | 用户点击鼠标左键 |
| <KeyPress-H> | 用户点击 H 按键 |
| <Control-Shift-KeyPress-H> | 用户同时点击 Ctrl + Shift + H |
type
| type | 含义 |
| Activate | 当组件的状态从“未激活”变为“激活”的时候触发该事件 |
| Button | 1. 当用户点击鼠标按键的时候触发该事件 2. detail 部分指定具体哪个按键:<Button-1>鼠标左键,<Button-2>鼠标中键,<Button-3>鼠标右键,<Button-4>滚轮上滚(Linux),<Button-5>滚轮下滚(Linux) |
| ButtonRelease | 1. 当用户释放鼠标按键的时候触发该事 2. 在大多数情况下,比 Button 要更好用,因为如果当用户不小心按下鼠标,用户可以将鼠标移出组件再释放鼠标,从而避免不小心触发事件 |
| Configure | 当组件的尺寸发生改变的时候触发该事件 |
| Deactivate | 当组件的状态从“激活”变为“未激活”的时候触发该事件 |
| Destroy | 当组件被销毁的时候触发该事件 |
| Enter | 1. 当鼠标指针进入组件的时候触发该事件 2. 注意:不是指用户按下回车键 |
| Expose | 当窗口或组件的某部分不再被覆盖的时候触发该事件 |
| FocusIn | 1. 当组件获得焦点的时候触发该事件 2. 用户可以用 Tab 键将焦点转移到该组件上(需要该组件的 takefocus 选项为 True) 3. 你也可以调用 focus_set() 方法使该组件获得焦点(见上方例子) |
| FocusOut | 当组件失去焦点的时候触发该事件 |
| KeyPress | 1. 当用户按下键盘按键的时候触发该事件 2. detail 可以指定具体的按键,例如 <KeyPress-H>表示当大写字母 H 被按下的时候触发该事件 3. KeyPress 可以简写为 Key |
| KeyRelease | 当用户释放键盘按键的时候触发该事件 |
| Leave | 当鼠标指针离开组件的时候触发该事件 |
| Map | 1. 当组件被映射的时候触发该事件 2. 意思是在应用程序中显示该组件的时候,例如调用 grid() 方法 |
| Motion | 当鼠标在组件内移动的整个过程均触发该事件 |
| MouseWheel | 1. 当鼠标滚轮滚动的时候触发该事件 2. 目前该事件仅支持 Windows 和 Mac 系统,Linux 系统请参考 Button |
| Unmap | 1. 当组件被取消映射的时候触发该事件 2. 意思是在应用程序中不再显示该组件的时候,例如调用 grid_remove() 方法 |
| Visibility | 当应用程序至少有一部分在屏幕中是可见的时候触发该事件 |
modifier
在事件序列中,modifier 部分的内容可以是以下这些:
| modifier | 含义 |
| Alt | 当按下 Alt 按键的时候 |
| Any | 1. 表示任何类型的按键被按下的时候 2. 例如 <Any-KeyPress> 表示当用户按下任何按键时触发事件 |
| Control | 当按下 Ctrl 按键的时候 |
| Double | 1. 当后续两个事件被连续触发的时候 2. 例如 <Double-Button-1> 表示当用户双击鼠标左键时触发事件 |
| Lock | 当打开大写字母锁定键(CapsLock)的时候 |
| Shift | 当按下 Shift 按键的时候 |
| Triple | 跟 Double 类似,当后续三个事件被连续触发的时候 |
Event 对象
当 Tkinter 去回调你定义的函数的时候,都会带着 Event 对象(作为参数)去调用,Event 对象以下这些属性你可以使用:
| 属性 | 含义 |
| widget | 产生该事件的组件 |
| x, y | 当前的鼠标位置坐标(相对于窗口左上角,像素为单位) |
| x_root, y_root | 当前的鼠标位置坐标(相对于屏幕左上角,像素为单位) |
| char | 按键对应的字符(键盘事件专属) |
| keysym | 按键名,见下方 Key names(键盘事件专属) |
| keycode | 按键码,见下方 Key names(键盘事件专属) |
| num | 按钮数字(鼠标事件专属) |
| width, height | 组件的新尺寸(Configure 事件专属) |
| type | 该事件类型 |
Key names
当事件为 <Key>,<KeyPress>,<KeyRelease> 的时候,detail 可以通过设定具体的按键名(keysym)来筛选。例如 <Key-H> 表示按下键盘上的大写字母 H 时候触发事件,<Key-Tab> 表示按下键盘上的 Tab 按键的时候触发事件。
下表列举了键盘所有特殊按键的 keysym 和 keycode:
(下边按键码是对应美国标准 101 键盘的“Latin-1”字符集,键盘标准不同对应的按键码不同,但按键名是一样的)
| 按键名(keysym) | 按键码(keycode) | 代表的按键 |
| Alt_L | 64 | 左边的 Alt 按键 |
| Alt_R | 113 | 右边的 Alt 按键 |
| BackSpace | 22 | Backspace(退格)按键 |
| Cancel | 110 | break 按键 |
| Caps_Lock | 66 | CapsLock(大写字母锁定)按键 |
| Control_L | 37 | 左边的 Ctrl 按键 |
| Control_R | 109 | 右边的 Ctrl 按键 |
| Delete | 107 | Delete 按键 |
| Down | 104 | ↓ 按键 |
| End | 103 | End 按键 |
| Escape | 9 | Esc 按键 |
| Execute | 111 | SysReq 按键 |
| F1 | 67 | F1 按键 |
| F2 | 68 | F2 按键 |
| F3 | 69 | F3 按键 |
| F4 | 70 | F4 按键 |
| F5 | 71 | F5 按键 |
| F6 | 72 | F6 按键 |
| F7 | 73 | F7 按键 |
| F8 | 74 | F8 按键 |
| F9 | 75 | F9 按键 |
| F10 | 76 | F10 按键 |
| F11 | 77 | F11 按键 |
| F12 | 96 | F12 按键 |
| Home | 97 | Home 按键 |
| Insert | 106 | Insert 按键 |
| Left | 100 | ← 按键 |
| Linefeed | 54 | Linefeed(Ctrl + J) |
| KP_0 | 90 | 小键盘数字 0 |
| KP_1 | 87 | 小键盘数字 1 |
| KP_2 | 88 | 小键盘数字 2 |
| KP_3 | 89 | 小键盘数字 3 |
| KP_4 | 83 | 小键盘数字 4 |
| KP_5 | 84 | 小键盘数字 5 |
| KP_6 | 85 | 小键盘数字 6 |
| KP_7 | 79 | 小键盘数字 7 |
| KP_8 | 80 | 小键盘数字 8 |
| KP_9 | 81 | 小键盘数字 9 |
| KP_Add | 86 | 小键盘的 + 按键 |
| KP_Begin | 84 | 小键盘的中间按键(5) |
| KP_Decimal | 91 | 小键盘的点按键(.) |
| KP_Delete | 91 | 小键盘的删除键 |
| KP_Divide | 112 | 小键盘的 / 按键 |
| KP_Down | 88 | 小键盘的 ↓ 按键 |
| KP_End | 87 | 小键盘的 End 按键 |
| KP_Enter | 108 | 小键盘的 Enter 按键 |
| KP_Home | 79 | 小键盘的 Home 按键 |
| KP_Insert | 90 | 小键盘的 Insert 按键 |
| KP_Left | 83 | 小键盘的 ← 按键 |
| KP_Multiply | 63 | 小键盘的 * 按键 |
| KP_Next | 89 | 小键盘的 PageDown 按键 |
| KP_Prior | 81 | 小键盘的 PageUp 按键 |
| KP_Right | 85 | 小键盘的 → 按键 |
| KP_Subtract | 82 | 小键盘的 - 按键 |
| KP_Up | 80 | 小键盘的 ↑ 按键 |
| Next | 105 | PageDown 按键 |
| Num_Lock | 77 | NumLock(数字锁定)按键 |
| Pause | 110 | Pause(暂停)按键 |
| 111 | PrintScrn(打印屏幕)按键 | |
| Prior | 99 | PageUp 按键 |
| Return | 36 | Enter(回车)按键 |
| Right | 102 | → 按键 |
| Scroll_Lock | 78 | ScrollLock 按键 |
| Shift_L | 50 | 左边的 Shift 按键 |
| Shift_R | 62 | 右边的 Shift 按键 |
| Tab | 23 | Tab(制表)按键 |
| Up | 98 | ↑ 按键 |


















