Tkinter does not pass events to parent widgets. However, you can simulate the effect through the use of bind tags (or "bindtags").
The shortest explanation I can give is this: when you add bindings to a widget, you aren't adding a binding to a widget, you are binding to a "bind tag". This tag has the same name as the widget, but it's not actually the widget.
Widgets have a list of bind tags, so when an event happens on a widget, the bindings for each tag are processed in order. Normally the order is:
- bindings on the actual widget
- bindings on the widget class
- bindings on the toplevel widget that contains the widget
- bindings on "all"
Notice that nowhere in that list is "bindings on the parent widget".
You can insert your own bindtags into that order. So, for example, you can add the main canvas to the bind tags of each sub-canvas. When you bind to either, the function will get called. Thus, it will appear that the event is passed to the parent.
Here's some example code written in python 2.7. If you click on a gray square you'll see two things printed out, showing that both the binding on the sub-canvas and the binding on the main canvas fire. If you click on a pink square you'll see that the sub-canvas binding fires, but it prevents the parent binding from firing.
With that, all button clicks are in effect "passed" to the parent. The sub-canvas can control whether the parent should handle the event or not, by returning "break" if it wants to "break the chain" of event processing.
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()