Search code examples
pythonuser-interfacewxpythonframe

Making top window inaccessible in wx.python


How can I make top frame inaccessible while child frame is open?

import wx

class MyFrame(wx.Frame):
    def __init__(self, parent, title):
        wx.Frame.__init__(self, parent, title=title, size=(400, 320), style=(wx.MINIMIZE_BOX | wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX | wx.CLIP_CHILDREN))

        # Setting up menu
        filemenu = wx.Menu()
        set_m = filemenu.Append(wx.ID_PREFERENCES, 'Settings', 'Settings')
        # filemenu.Append(US)
        filemenu.AppendSeparator()
        exit_m = filemenu.Append(wx.ID_EXIT)

        # Creating the menubar
        menubar = wx.MenuBar()
        menubar.Append(filemenu, 'Menu')
        self.SetMenuBar(menubar)

        self.Bind(wx.EVT_MENU, self.OnSettings, set_m)

    def OnSettings(self, e):
        SetFrame().Show()

class SetFrame(wx.Frame):
    title = 'Settings'
    def __init__(self):
        wx.Frame.__init__(self, wx.GetApp().TopWindow, title=self.title, size=(400, 250), style=(wx.MINIMIZE_BOX | wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX | wx.CLIP_CHILDREN))


class MyApp (wx.App):
    def OnInit(self):
        self.frame = MyFrame(None, title='Parent-Frame')
        self.frame.Show()
        self.SetTopWindow(self.frame)
        return True

if __name__ == '__main__':
    app = MyApp(0)
    app.MainLoop()

Solution

  • You can also make the second frame modal just like a dialog. Here's your code modified to do just that:

    import wx
    
    class MyFrame(wx.Frame):
        def __init__(self, parent, title):
            wx.Frame.__init__(self, parent, title=title, size=(400, 320), style=(wx.MINIMIZE_BOX | wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX | wx.CLIP_CHILDREN))
    
            # Setting up menu
            filemenu = wx.Menu()
            set_m = filemenu.Append(wx.ID_PREFERENCES, 'Settings', 'Settings')
            # filemenu.Append(US)
            filemenu.AppendSeparator()
            exit_m = filemenu.Append(wx.ID_EXIT)
    
            # Creating the menubar
            menubar = wx.MenuBar()
            menubar.Append(filemenu, 'Menu')
            self.SetMenuBar(menubar)
    
            self.Bind(wx.EVT_MENU, self.OnSettings, set_m)
    
        def OnSettings(self, e):
            SetFrame().Show()
    
    class SetFrame(wx.Frame):
        title = 'Settings'
        def __init__(self):
            wx.Frame.__init__(self, wx.GetApp().TopWindow, title=self.title, size=(400, 250), style=(wx.MINIMIZE_BOX | wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX | wx.CLIP_CHILDREN))
            self.Bind(wx.EVT_CLOSE, self.onClose)
            self.MakeModal()
    
        #----------------------------------------------------------------------
        def onClose(self, event):
            """
            Make the frame non-modal as it closes to re-enable other windows
            """
            self.MakeModal(False)
            self.Destroy()
    
    class MyApp (wx.App):
        def OnInit(self):
            self.frame = MyFrame(None, title='Parent-Frame')
            self.frame.Show()
            self.SetTopWindow(self.frame)
            return True
    
    if __name__ == '__main__':
        app = MyApp(0)
        app.MainLoop()
    

    Note that you have to disable the modality when you close the settings frame to re-enable the other windows. See http://wxpython-users.1045709.n5.nabble.com/making-a-frame-modal-td2363708.html for more information.