The other day, I came across an interesting StackOverflow question where the fellow was trying to figure out how to open a sub-frame only once. Basically he wanted a single instance of the sub-frame (and other sub-frames). After digging around a bit on Google, I found an old thread from the wxPython Google Group that had an interesting approach to doing what was needed.
Basically it required a bit of meta-programming, but it was a fun little exercise that I thought my readers would find interesting. Here's the code:
import wx ######################################################################## class MyPanel(wx.Panel): """""" #---------------------------------------------------------------------- def __init__(self, parent): """Constructor""" wx.Panel.__init__(self, parent) ######################################################################## class SingleInstanceFrame(wx.Frame): """""" instance = None init = 0 #---------------------------------------------------------------------- def __new__(self, *args, **kwargs): """""" if self.instance is None: self.instance = wx.Frame.__new__(self) elif isinstance(self.instance, wx._core._wxPyDeadObject): self.instance = wx.Frame.__new__(self) return self.instance #---------------------------------------------------------------------- def __init__(self): """Constructor""" print id(self) if self.init: return self.init = 1 wx.Frame.__init__(self, None, title="Single Instance Frame") panel = MyPanel(self) self.Show() ######################################################################## class MainFrame(wx.Frame): """""" #---------------------------------------------------------------------- def __init__(self): """Constructor""" wx.Frame.__init__(self, None, title="Main Frame") panel = MyPanel(self) btn = wx.Button(panel, label="Open Frame") btn.Bind(wx.EVT_BUTTON, self.open_frame) self.Show() #---------------------------------------------------------------------- def open_frame(self, event): frame = SingleInstanceFrame() if __name__ == '__main__': app = wx.App(False) frame = MainFrame() app.MainLoop()
The meat of this code is in the SingleInstanceFrame class, specifically in the __new__ method. Here we check to see if the variable self.instance is set to None. If so, we create a new instance. We will also create a new instance if the user closes the frame, which will cause it to become a wxPyDeadObject. This is what the second part of the if statement is for. It checks to see if the instance has been deleted and if it has, it creates a new instance.
You will also notice that we have a variable called self.init. This is used to check if the instance has already been initialized. If so, __init__ will just return instead of re-instantiating everything.
In wxPython 4 / Phoenix, there is no wx._core._wxPyDeadObject, so we have to modify our code a bit to make it work in the newer versions of wxPython. Here's how:
import wx class MyPanel(wx.Panel): """""" def __init__(self, parent): """Constructor""" wx.Panel.__init__(self, parent) class SingleInstanceFrame(wx.Frame): """""" instance = None init = 0 def __new__(self, *args, **kwargs): """""" if self.instance is None: self.instance = wx.Frame.__new__(self) elif not self.instance: self.instance = wx.Frame.__new__(self) return self.instance def __init__(self): """Constructor""" print(id(self)) if self.init: return self.init = 1 wx.Frame.__init__(self, None, title="Single Instance Frame") panel = MyPanel(self) self.Show() class MainFrame(wx.Frame): """""" def __init__(self): """Constructor""" wx.Frame.__init__(self, None, title="Main Frame") panel = MyPanel(self) btn = wx.Button(panel, label="Open Frame") btn.Bind(wx.EVT_BUTTON, self.open_frame) self.Show() def open_frame(self, event): frame = SingleInstanceFrame() if __name__ == '__main__': print wx.version() app = wx.App(False) frame = MainFrame() app.MainLoop()
You will note that the only difference is found in the __new__ method where we changed the conditional statements slightly.
I hope you've found this tutorial useful. Have fun and happy coding!
Copyright © 2024 Mouse Vs Python | Powered by Pythonlibrary