代码之家  ›  专栏  ›  技术社区  ›  steffen

如何将事件传递给父tkinter小部件?

  •  3
  • steffen  · 技术社区  · 10 年前

    在Tkinter中是否可以将事件直接传递给父控件?

    我有一张画布,上面覆盖着其他画布的网格(这是复数吗?),我使用 parent_canvas.create_window() 方法我希望一些事件,例如鼠标释放事件,由父画布处理。

    如果我只将事件绑定到父方法 event.x event.y 坐标是相对于捕捉事件的子画布的。

    1 回复  |  直到 5 年前
        1
  •  9
  •   Bryan Oakley    10 年前

    Tkinter不会将事件传递给父控件。但是,您可以通过使用绑定标记(或“bindtags”)来模拟效果。

    我可以给出的最简短的解释是:当您向小部件添加绑定时,您不是在向小部件中添加绑定,而是绑定到“绑定标签”。此标记与小部件同名,但实际上不是小部件。

    小部件有一个绑定标记列表,因此当小部件上发生事件时,每个标记的绑定都会按顺序处理。通常顺序为:

    1. 实际小部件上的绑定
    2. 小部件类上的绑定
    3. 包含小部件的顶层小部件上的绑定
    4. “all”上的绑定

    请注意,该列表中没有任何地方是“父小部件上的绑定”。

    您可以将自己的bindtag插入到该顺序中。例如,您可以将主画布添加到每个子画布的绑定标记中。当您绑定到其中一个时,函数将被调用。因此,事件似乎传递给了父级。

    下面是用python 2.7编写的一些示例代码。如果单击灰色正方形,您将看到打印出两个内容,显示子画布上的绑定和主画布上的约束都会发生火灾。如果单击粉色正方形,您将看到子画布绑定激发,但它阻止父绑定激发。

    这样,所有的按钮点击实际上都“传递”给了父级。子画布可以通过返回“break”来控制父画布是否应该处理事件,如果它想“断开”事件处理链。

    import Tkinter as tk
    
    class Example(tk.Frame):
        def __init__(self, parent):
            tk.Frame.__init__(self, parent)
    
            self.main = tk.Canvas(self, width=400, height=400, 
                                  borderwidth=0, highlightthickness=0,
                                  background="bisque")
            self.main.pack(side="top", fill="both", expand=True)
    
            # add a callback for button events on the main canvas
            self.main.bind("<1>", self.on_main_click)
    
            for x in range(10):
                for y in range(10):
                    canvas = tk.Canvas(self.main, width=48, height=48, 
                                       borderwidth=1, highlightthickness=0,
                                       relief="raised")
                    if ((x+y)%2 == 0):
                        canvas.configure(bg="pink")
    
                    self.main.create_window(x*50, y*50, anchor="nw", window=canvas)
    
                    # adjust the bindtags of the sub-canvas to include
                    # the parent canvas
                    bindtags = list(canvas.bindtags())
                    bindtags.insert(1, self.main)
                    canvas.bindtags(tuple(bindtags))
    
                    # add a callback for button events on the inner canvas
                    canvas.bind("<1>", self.on_sub_click)
    
    
        def on_sub_click(self, event):
            print "sub-canvas binding"
            if event.widget.cget("background") == "pink":
                return "break"
    
        def on_main_click(self, event):
            print "main widget binding"
    
    if __name__ == "__main__":
        root = tk.Tk()
        Example(root).pack (fill="both", expand=True)
        root.mainloop()