Detect main 'close button' was clicked from overriden TopLevel widget

91 Views Asked by At

I just want to close/destroy an overriden TopLevel widget when the main close button ('X' button) is clicked. The overriden TopLevel widget is not created from the root of tKinter, but from a frame.

class MyToplevel(Tki.Toplevel):
    def __init__(self, parent, *args, **kwargs):  # parent is not the root of tKinter, it's a frame
        super().__init__(*args, **kwargs)
        self.protocol("WM_DELETE_WINDOW", self.on_closing)  # Not working
        self.wm_protocol("WM_DELETE_WINDOW", self.on_closing)  # Not working

    def on_closing(self):
        # The key is, how can I call this method when main close button is clicked?
        self.destroy()

I also have tried self.winfo_ismapped() and self.winfo_exists(), but when I click in the close button, nothing happens, because the main window exists.

1

There are 1 best solutions below

7
acw1668 On

If you want to close the toplevel when the close button ("X") on the root window is clicked, then you need to bind the protocol "WM_DELETE_WINDOW" on the root window as well:

class MyToplevel(Tki.Toplevel):
    def __init__(self, parent, *args, **kwargs):  # parent is not the root of tKinter, it's a frame
        super().__init__(parent, *args, **kwargs)

        # find root window
        self.root = self.winfo_toplevel()
        while self.root.master:
            self.root = self.root.master.winfo_toplevel()

        self.handler = self.root.protocol("WM_DELETE_WINDOW")
        self.root.protocol("WM_DELETE_WINDOW", self.on_closing)
        self.protocol("WM_DELETE_WINDOW", self.on_closing)

    def on_closing(self):
        # restore default handler for root window
        self.root.protocol("WM_DELETE_WINDOW", self.handler)
        self.destroy()

Note that this does not work when more than one toplevel is open simultaneously.