如何在Tkinter中实现嵌套类间的事件通信?
Tkinter自定义事件跨类触发问题解决
问题原因
你当前的代码里,Nested类调用self.event_generate("<<MyEvent>>")时,只会在Nested这个Frame实例上生成事件,但Main类是在自己的实例上绑定的<<MyEvent>>。Tkinter的自定义虚拟事件默认不会向上传播,所以Main的绑定无法捕获到Nested实例上生成的事件。
解决方案
方案1:直接在目标组件上生成事件
既然Main类是事件的绑定者,就让Nested在Main的实例上生成事件。修改Nested的__init__方法,把self.event_generate换成针对父组件(即Main实例)的调用:
import tkinter as tk root = tk.Tk() class Main(tk.Frame): class Nested(tk.Frame): def __init__(self, parent) -> None: tk.Frame.__init__(self, parent) # 改为在父组件(Main实例)上生成事件 parent.event_generate("<<MyEvent>>", when="tail") def __init__(self, parent) -> None: tk.Frame.__init__(self, parent) self.event_add("<<MyEvent>>", "<Button-1>") self.bind("<<MyEvent>>", self.foo) self.nested = self.Nested(self) self.nested.grid(column=0, row=0) def foo(self, event): print("event occured") main = Main(root) main.grid(column=0, row=0) root.mainloop()
方案2:全局触发(顶层窗口级别)
如果需要让事件在整个应用内全局生效,可以把事件绑定到顶层窗口(root),然后在Nested里向顶层窗口生成事件:
import tkinter as tk root = tk.Tk() class Main(tk.Frame): class Nested(tk.Frame): def __init__(self, parent) -> None: tk.Frame.__init__(self, parent) # 向顶层窗口生成事件 self.winfo_toplevel().event_generate("<<MyEvent>>", when="tail") def __init__(self, parent) -> None: tk.Frame.__init__(self, parent) self.event_add("<<MyEvent>>", "<Button-1>") # 把绑定移到顶层窗口 parent.bind("<<MyEvent>>", self.foo) self.nested = self.Nested(self) self.nested.grid(column=0, row=0) def foo(self, event): print("event occured") main = Main(root) main.grid(column=0, row=0) root.mainloop()
额外说明
你之前尝试用winfo_toplevel()没效果,是因为事件绑定在Main实例上,而不是顶层窗口。只要把绑定目标和事件生成目标对应起来,就能解决问题,不需要调整整体GUI结构。
内容的提问来源于stack exchange,提问作者domino280d




