问题描述
在下面的块中,单击 a_frame
触发事件处理程序 on_frame_click
,但点击 a_label
是 a_frame
的孩子。有没有办法强制 a_frame
来捕获和处理起源于它的孩子的事件(最好不必直接向孩子添加处理程序)?我使用Python 3.2.3。
In the following block, clicking on a_frame
triggers the event handler on_frame_click
, but clicking on a_label
which is a child of a_frame
does not. Is there a way to force a_frame
to trap and handle events which originated on it's children (preferably with out having to add handlers to the children directly)? I am using Python 3.2.3.
import tkinter
def on_frame_click(e):
print("frame clicked")
tk = tkinter.Tk()
a_frame = tkinter.Frame(tk, bg="red", padx=20, pady=20)
a_label = tkinter.Label(a_frame, text="A Label")
a_frame.pack()
a_label.pack()
tk.protocol("WM_DELETE_WINDOW", tk.destroy)
a_frame.bind("<Button>", on_frame_click)
tk.mainloop()
推荐答案
是的,你可以做你想要的,但需要一些工作。它不是不支持,只是它实际上很少需要这样的东西,所以它不是默认的行为。
Yes, you can do what you want, but it requires a bit of work. It's not that it's not supported, it's just that it's actually quite rare to need something like this so it's not the default behavior.
TL; DR - 研究 tkinter绑定标签
Tkinter事件模型包含绑定标签的概念。这是与每个小部件相关联的标签列表。当在窗口小部件上收到事件时,将检查每个绑定标签,以查看它是否具有事件的绑定。如果是这样,则调用处理程序。如果没有,它继续。如果一个处理程序返回break,那么该链就被破坏了,而且没有更多的标签被考虑。
The Tkinter event model includes the notion of "bind tags". This is a list of tags associated with each widget. When an event is received on a widget, each bind tag is checked to see if it has a binding for the event. If so, the handler is called. If not, it continues on. If a handler returns "break", the chain is broken and no more tags are considered.
默认情况下,widget的绑定标签是widget本身,类,小部件所在的toplevel窗口的标签,最后是特殊标签all。但是,您可以在其中放置任何您想要的标签,您可以更改订单。
By default, the bind tags for a widget are the widget itself, the widget class, the tag for the toplevel window the widget is in, and finally the special tag "all". However, you can put any tags you want in there, and you can change the order.
所有这些的实际结果?您可以将自己的唯一标签添加到每个窗口小部件,然后向该标签添加一个绑定,该标签将由所有窗口小部件处理。这里有一个例子,使用您的代码作为起点(我添加了一个按钮小部件,以显示这不是特殊的框架和标签):
The practical upshot of all this? You can add your own unique tag to every widget, then add a single binding to that tag that will be processed by all widgets. Here's an example, using your code as a starting point (I added a button widget, to show this isn't something special just for frames and labels):
import Tkinter as tkinter
def on_frame_click(e):
print("frame clicked")
def retag(tag, *args):
'''Add the given tag as the first bindtag for every widget passed in'''
for widget in args:
widget.bindtags((tag,) + widget.bindtags())
tk = tkinter.Tk()
a_frame = tkinter.Frame(tk, bg="red", padx=20, pady=20)
a_label = tkinter.Label(a_frame, text="A Label")
a_button = tkinter.Button(a_frame, text="click me!")
a_frame.pack()
a_label.pack()
a_button.pack()
tk.protocol("WM_DELETE_WINDOW", tk.destroy)
retag("special", a_frame, a_label, a_button)
tk.bind_class("special", "<Button>", on_frame_click)
tk.mainloop()
有关bindtags的更多信息,可以是int在中回答了问题如何在Tkinter文本小部件绑定自己的事件之后绑定Text文件?答案涉及与这里不同的问题,但它显示了使用绑定标签来解决现实世界问题的另一个例子。
For more on bindtags, you might be interested in my answer to the question How to bind self events in Tkinter Text widget after it will binded by Text widget?. The answer addresses a different question than the one here, but it shows another example of using bind tags to solve real world problems.
这篇关于如何捕获tkinter子窗口小部件上的事件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!