Confused about window closure event handling

I’m migrating from Qt and stuck trying to figure out how to get onExit in the toy script below to run no matter if I click the red X or use the menu item to exit the program. Is there another event I need to bind to or a method that needs overridden?

import wx

def onExit(event):
    print("onExit ran.")

app = wx.App()

window = wx.Frame(None)

menubar = wx.MenuBar()
window.SetMenuBar(menubar)

filemenu = wx.Menu()
menubar.Append(filemenu, "File")

menuexit = filemenu.Append(wx.ID_EXIT, "Exit")
window.Bind(wx.EVT_MENU, onExit, menuexit)

window.Show()

app.MainLoop()

Hi, zspinelli

Normally, call window.Close() in onExit.

To see more details, please try this snippet.

import wx

class Frame(wx.Frame):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        menubar = wx.MenuBar()
        self.SetMenuBar(menubar)

        filemenu = wx.Menu()
        menubar.Append(filemenu, "File")

        menuexit = filemenu.Append(wx.ID_EXIT, "Exit\tCtrl-q")
        self.Bind(wx.EVT_MENU, self.onExit, menuexit)

        self.Bind(wx.EVT_CLOSE, self.onClose)
        self.Bind(wx.EVT_WINDOW_DESTROY, self.onDestroy)

    def onExit(self, evt): #<wx._core.CommandEvent>
        print("evt =", evt)
        self.Close()

    def onClose(self, evt): #<wx._core.CloseEvent>
        print("evt =", evt)
        evt.Skip()

    def onDestroy(self, evt): #<wx._core.WindowDestroyEvent>
        print("evt =", evt)
        evt.Skip()

    def Destroy(self):
        print("Frame:Destroy is called")
        return wx.Frame.Destroy(self)

app = wx.App()
frm = Frame(None)
frm.Show()
app.MainLoop()

You may observe:

evt = <wx._core.CommandEvent object at 0x000001BD469AAD30>
evt = <wx._core.CloseEvent object at 0x000001BD469AE0D0>
Frame:Destroy is called
evt = <wx._core.WindowDestroyEvent object at 0x000001BD469AAD30>

When exiting the program, call Close. Then, EVT_CLOSE will be triggered. The EVT_CLOSE is also triggered when the [x] button is clicked.
In the CloseEvent handler, you have a chance to decide whether to close your app. For example, if you have unsaved something, you may want to pop up yes-or-no-dialog and ask the users if they really want to close it (see more details: wx.CloseEvent — wxPython Phoenix 4.1.2a1 documentation).
Finally, the system calls Destroy (this is only for the top level window). Then, EVT_WINDOW_DESTROY is triggered. The child windows or controls are destroyed automatically, but you need to destroy unparented windows, such as timer objects (see more details: Window Deletion Overview — wxPython Phoenix 4.1.2a1 documentation).

1 Like