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): """"""ifself.instanceisNone: self.instance = wx.Frame.__new__(self)elifisinstance(self.instance, wx._core._wxPyDeadObject): self.instance = wx.Frame.__new__(self)returnself.instance #----------------------------------------------------------------------def__init__(self): """Constructor"""printid(self)ifself.init: returnself.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. Anyway, I hope you found that enlightening. Happy coding!
Related Reading
- One Instance Running
- wx.SingleInstanceChecker documentation