tkinter是安装python后自带的一个GUI库,并不是很好用,但是好就好在这个GUI库是安装自带的。笔者比较喜欢wxPython,但是还需要单独安装。
想要了解tkinter的绑定事件,可以查看tkinter的帮助文档,具体运行这么一段代码就可以看到:
import tkinter as tk
help(tk.Tk.bind)
其中有一段介绍:
An event pattern is of the form <MODIFIER-MODIFIER-TYPE-DETAIL>
…
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
…
容我吐槽一下,这个帮助文档甚至还有错误,有一些该有逗号的地方(比如“Gravity Reparent”)中间也没有逗号,并且也没有处在文档的换行位置。初学者看了还以为是一个事件的名字,实际上是两个事件。
(关于这一点,还可以在idlelib.multicall库的_types参数看到关于事件的定义,可以证明这一点)
随后写了一个测试小组件的所有事件的响应效果的程序,代码如下:
import re
import tkinter as tk
# help(tk.Tk.bind)
__doc__ = '''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'''
events = re.findall(r'\w+', __doc__)
print(len(events))
events_used = []
def callback(ename):
def f(e):
if ename not in events_used:
events_used.append(ename)
print('%02d'%len(events_used), ename.ljust(15), e)
return f
top = tk.Tk()
txt = tk.Text(top)
for ename in events:
txt.bind('<%s>'%ename, callback(ename))
txt.pack(fill='both', expand=1)
# tk.Button(top, text='forget', command=lambda: txt.forget()).pack()
top.mainloop()
nouse = [ename for ename in events if ename not in events_used]
print('Not use:')
print(nouse)
print(len(nouse))
方法很简单,首先通过正则表达式的方法获取到帮助文档中提到的所有事件名,总共有25种事件。
不过其中的“Button”和“ButtonPress”是一样的,“Key”和“KeyPress”是一样的,所以实际上是有23种事件。
然后逐一绑定到tkinter的Text控件上,在出现事件的时候打印事件名和事件类。
不过类似于<Motion>这样的事件会很容易触发,为了避免刷屏,我用一行代码:
if ename not in events_used:
# print log ...
控制事件只在第一次触发的时候打印。如果希望持续打印输出,把这里改成:
if ename not in events_used or True:
就可以不断显示。
事件触发的条件大部分比较好理解,详细的解释在这一篇文章里也有介绍,可以看看:《python | tkinter(六) bind事件信息》
其中<Visibility>会在从最小化恢复窗口的时候触发,<Expose>会在窗口激活且显示面积增加(减少不会),比如恢复窗口和在窗口边缘移动的时候触发。
<Unmap>事件可以通过取消放置,在控件运行txt.forget()函数的时候会触发,不过在最小化的时候也会触发。(所以我把那段代码注释掉了)
运行的事件记录大概像这个样子:
01 Configure <Configure event x=0 y=0 width=564 height=316>
02 Map <Map event>
03 Visibility <Visibility event state=VisibilityUnobscured>
04 Expose <Expose event x=0 y=0 width=564 height=316>
05 Enter <Enter event state=Mod1 focus=False x=556 y=173>
06 Motion <Motion event state=Mod1 x=339 y=152>
07 Button <ButtonPress event state=Mod1 num=1 x=208 y=153>
08 FocusIn <FocusIn event>
09 ButtonRelease <ButtonRelease event state=Mod1|Button1 num=1 x=208 y=153>
10 MouseWheel <MouseWheel event state=Mod1 delta=-120 x=208 y=152>
11 Key <KeyPress event state=Mod1 keysym=Shift_L keycode=16 x=208 y=154>
12 KeyRelease <KeyRelease event state=Shift|Mod1 keysym=Shift_L keycode=16 x=208 y=154>
13 Leave <Leave event state=Mod1 focus=False x=678 y=161>
14 FocusOut <FocusOut event>
15 Unmap <Unmap event>
16 Destroy <Destroy event>
排除掉含义相同的**Press事件后,仍然有7个事件我没有试出来在什么情况下可以触发:
['Activate', 'Deactivate', 'Property', 'Colormap', 'Gravity', 'Reparent', 'Circulate']
如果有知道的童鞋欢迎在文章里留言告诉我测试能够展示的方法。
不过后来我看到了这一篇文章,感觉大意是说这些方法都是没用的,仅供参考:《tk中的事件类型》