Anders Petersson
Anders Petersson

Reputation: 391

Exiting a wxPython application with multiple windows

My wxPython application consists of a main window and an arbitrary number of secondary windows that the user can choose to launch. When the user closes the main window, I want the application to exit (and all other windows to close too, naturally). The standard behavior is for the application to exit only when the user closes the last window.

Do I need to program a global list of all windows, just to iterate and close them all to exit the application? Is my desired GUI behavior really so non-standard that it takes custom code to implement? I expected a simple App.exit() call or similar.

EDIT: I now found https://docs.wxpython.org/wx.PyApp.html#wx.PyApp.SetExitOnFrameDelete

Allows the programmer to specify whether the application will exit when the top-level frame is deleted.

But it doesn't work for me.

Here is a short example. Closing frame1 should exit the application, but it doesn't. It's necessary to close both windows.

import wx

class MainFrame(wx.Frame):
    def __init__(self, title, *args, **kwargs):
        super().__init__(None, *args, **kwargs)
        self.Title = title
        self.panel = MainPanel(self)
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.panel)
        self.SetSizer(sizer)
        self.Center()
        self.Show()

class MainPanel(wx.Panel):
    def __init__(self, parent, *args, **kwargs):
        super().__init__(parent, *args, **kwargs)
        sizer = wx.BoxSizer(wx.VERTICAL)
        self.SetSizer(sizer)

if __name__ == '__main__':
    wx_app = wx.App()
    frame1 = MainFrame("Close me to exit")
    frame2 = MainFrame("Secondary window")
    wx_app.SetTopWindow(frame1)
    wx_app.SetExitOnFrameDelete(True)
    wx_app.MainLoop()

Upvotes: 1

Views: 86

Answers (1)

Rolf of Saxony
Rolf of Saxony

Reputation: 22443

The issue is that you have 2 top level frames.
The App closes when the last top level frame closes, so usually there is 1 top level frame and subsequent frames have that as their parent.
With this arrangement, when the parent closes, the child frames close as well.
See: https://docs.wxpython.org/app_overview.html#application-shutdown
Alternatively see: https://docs.wxpython.org/wx.functions.html#wx.Exit

For your example:

import wx

class MainFrame(wx.Frame):
    def __init__(self, title, *args, **kwargs):
        super().__init__(None, *args, **kwargs)
        self.Title = title
        self.panel = MainPanel(self)
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.panel)
        self.SetSizer(sizer)
        self.Center()
        self.Show()
        self.Bind(wx.EVT_CLOSE, self.OnClose)
        self.frame2 = SecondaryFrame(parent=self, title="Secondary")

    def OnClose(self, event):
        self.Destroy()

class MainPanel(wx.Panel):
    def __init__(self, parent, *args, **kwargs):
        super().__init__(parent, *args, **kwargs)
        sizer = wx.BoxSizer(wx.VERTICAL)
        self.SetSizer(sizer)

class SecondaryFrame(wx.Frame):
    def __init__(self, parent, title):
        super().__init__(parent)
        self.Title = title
        self.panel = MainPanel(self)
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.panel)
        self.SetSizer(sizer)
        self.Bind(wx.EVT_CLOSE, self.OnClose)
        self.Center()
        self.Show()

    def OnClose(self, event):
        self.Destroy()

if __name__ == '__main__':
    wx_app = wx.App()
    frame = MainFrame("Close me to exit")
    wx_app.MainLoop()

Upvotes: 2

Related Questions