pythontkintertcl

How to make nested class event communication in Tkinter


I run into a problem with tkinter events. I tried to create event in class and call it from nested class. Event generates only on nested class level. Is there any way to generate event globally, or I need to change my GUI structure?

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.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()

I thought problem was in scope, but after trying to add between self and event_generate() winfo_toplevel(), nothing changed.


Solution

  • By default, events sent to a widget will route to (in this order):

    1. The widget's instance bindings.
    2. The widget's class bindings (Button for a button, etc.) This is only really useful when developing wholly new types of widget.
    3. The widget's toplevel instance bindings (great for keyboard accelerators). For toplevels, this is omitted.
    4. The global all bindings. Rarely used except for remapping key sequences.

    Nowhere in that list is any parent widget, with the sole exception of the owning toplevel, or any child widget.

    When you use self.bind, you work with the first category. This is strongly recommended as a way of working. (These defaults can be overridden, but that's a significantly more complex topic, with some very subtle consequences.)

    When generating an event, you really need to choose the correct target widget for the event; for the nested widget to send an event to the parent, it needs to use parent.event_generate(). I suggest you do that here.