Reputation: 1705
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()
Upvotes: 1
Views: 1383
Reputation: 3218
Nested modal dialogs were causing issues with my app so I ended up doing:
self.GetParent().Disable()
self.Enable()
self.Bind(wx.EVT_CLOSE, self.on_close)
def on_close(self, event):
event.Skip()
self.GetParent().Enable()
self.Destroy()
Disabling the parent also disables all child windows, but they can be re-enabled.
EDIT:
Also, adding wx.FRAME_FLOAT_ON_PARENT
and wx.FRAME_NO_TASKBAR
styles to wx.Frame.__init__
can help replicate the behavior of a modal dialog
Upvotes: 1
Reputation: 33071
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.
Upvotes: 1
Reputation: 3625
You could use a modal dialog instead although a modal dialog blocks the rest of the application and you might not want that.
To make your frame act like a modal dialog that doesn't block the application, when you open your child frame disable the parent frame, remembering to enable the parent frame again when the child frame closes.
Also its a good idea to set the style wx.FRAME_FLOAT_ON_PARENT on the child frame to keep it on top of its parent frame and setting it to centre on the parent frame.
I've modified you code below to make the top frame inaccessible while child frame is open.
import wx
class MyFrame(wx.Frame):
def __init__(self, parent, title):
style = (wx.MINIMIZE_BOX | wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX |
wx.CLIP_CHILDREN)
wx.Frame.__init__(self, parent, title=title, size=(400, 320),
style=style)
# 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):
style = (wx.MINIMIZE_BOX | wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX |
wx.CLIP_CHILDREN | wx.FRAME_FLOAT_ON_PARENT)
wx.Frame.__init__(self, wx.GetApp().TopWindow, title=self.title,
size=(400, 250), style=style)
self.CenterOnParent()
self.GetParent().Disable()
self.Bind(wx.EVT_CLOSE, self.onClose)
def onClose(self, event):
self.Close()
event.Skip()
def Close(self):
self.GetParent().Enable()
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()
Upvotes: 2