如何解决传播事件比在Widget中传播更远?
- 是否可以将事件发送给其他创建它的小部件?
我试图找到,但是我发现的所有教程和文档都没有产生任何效果。因此,我进行了以下实验:有一个简单的GUI树,如下所示:
root Tk()
|
+---- Frame a------+------------+
| | |
+---Frame b1--+ Frame b2 Label al
| | |
Frame c Label b1l Label b2l
|
Label cl
然后,我将b1
设置为在<<MyEvent>>
上检测到<Button-1>
时调用b1l
。此外,我将<<MyEvent>>
绑定到所有其他根节点。当运行程序并单击所述标签时,我只能看到b1
本身和root
对事件有反应,但亲戚都没有反应。因此看来,此事件只能由调用它的小部件和在根小部件中捕获。
-
但是有没有办法让其他任何小部件接收此事件?
-
还有谁能推荐涵盖此类内容的更全面的教程/文档?
我的实验代码如下
import tkinter
root = tkinter.Tk()
a = tkinter.Frame(master=root); a.pack()
al = tkinter.Label(master=a,text="label a "); al .pack()
b1 = tkinter.Frame(master=a); b1.pack()
b1l = tkinter.Label(master=b1,text="label b1"); b1l.pack()
c = tkinter.Frame(master=b1); c.pack()
cl = tkinter.Label(master=c,text="label c1 "); cl .pack()
b2 = tkinter.Frame(master=a); b2.pack()
b2l = tkinter.Label(master=b2,text="label b2"); b2l.pack()
root.bind('<<MyEvent>>',lambda *_: print("MyEvent caught in root"))
a. bind('<<MyEvent>>',lambda *_: print("MyEvent caught in a "))
al. bind('<<MyEvent>>',lambda *_: print("MyEvent caught in al "))
b1. bind('<<MyEvent>>',lambda *_: print("MyEvent caught in b1 "))
b1l. bind('<<MyEvent>>',lambda *_: print("MyEvent caught in b1l "))
b2. bind('<<MyEvent>>',lambda *_: print("MyEvent caught in b2 "))
b2l. bind('<<MyEvent>>',lambda *_: print("MyEvent caught in b2l "))
c. bind('<<MyEvent>>',lambda *_: print("MyEvent caught in c "))
cl. bind('<<MyEvent>>',lambda *_: print("MyEvent caught in cl "))
def cb(*x):
b1.event_generate('<<MyEvent>>')
b1l.bind('<Button-1>',cb)
root.mainloop()
解决方法
简而言之,事件不会传播。这根本不是事件在Tkinter中的工作方式。它们仅由接收事件的小部件处理。如果您希望每个小部件都收到<<MyEvent>>
事件,则必须在每个小部件上调用event_generate
。
即使您的代码使root也会收到事件,但事实并非如此。这就是为什么这样做的原因:
通过绑定调用函数时,将传递代表事件的对象。该对象的属性之一是widget
,它代表捕获事件的小部件。如果将其与已经打印过的字符串一起打印出来,则会看到它仅报告您单击过的标签。
例如,将您的绑定语句更改为如下形式:
...
root.bind('<<MyEvent>>',lambda event: print(f"MyEvent caught in root ({event.widget})"))
b1. bind('<<MyEvent>>',lambda event: print(f"MyEvent caught in b1 ({event.widget})"))
...
为便于阅读,请为您的每个小部件起一个这样的名称:
...
a = tkinter.Frame(master=root,name="a"); a.pack()
b1 = tkinter.Frame(master=a,name="b1"); b1.pack()
...
根窗口的名称为“。”。由于b1
是.a.b1
的子级,而b1
是根窗口的子级,因此a
的全名是a
。
当我这样做时,我单击b1l
,这是输出:
MyEvent caught in b1 (.a.b1)
MyEvent caught in root (.a.b1)
请注意,即使在“ root”正在处理事件的情况下,在两个打印语句中也显示.a.b1
。即使看起来像root一样正在获取事件,实际上它是b1
小部件来获取事件,但同时由b1
和root
上的绑定来处理。
原因是事件在tkinter中如何工作的基础。函数实际上并不绑定到小部件,而是绑定到绑定标签。每个小部件都有一组与之关联的绑定标签。默认情况下,这组绑定标签为:
- 窗口小部件的全名(例如:“。a.b1”)
- 窗口小部件的类别(“框架”)
- 根窗口的名称(“。”)
- 特殊标签“ all”
当b1
之类的小部件接收到一个事件时,tkinter将遍历绑定标签的列表并为该事件运行与每个标签关联的任何功能。因此,它是这样的:
-
b1
(“。a.b1”)上有一个绑定,因此该函数被调用 - “框架”没有绑定,所以什么也没叫
- 根窗口(“。”)上有一个绑定,因此该函数被调用
- 特殊标签“ all”上没有绑定。
在任何时候,如果被调用函数之一返回字符串"break"
,则该链将断开,并且将不再处理绑定标签。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。