Defining a wx.Panel destructor in wxpython

Question:

How do you define a destructor for a wx.Panel in wxpython?

META:
After inheriting a code base which uses wxpython and PyPubSub I’ve discovered a huge number of pubsub subscriptions in the __init__ functions of wx.Panel‘s that are never unsubscribed and cause errors later on in the program.

Asked By: Metalshark

||

Answers:

You should be able to bind to EVT_WINDOW_DESTROY and do the unsub in the handler.

For example:

class MyPanel(wx.Panel):

def __init__(self, parent):
    wx.Panel.__init__(self, parent, wx.NewId())

    pub.subscribe(self.__handler, 'event')

    def __destroy(_):
        pub.unsubscribe(self.__handler, 'event')

    self.Bind(wx.EVT_WINDOW_DESTROY, __destroy)

If above is not working you can protect against the PyDeadObjectError exception, by adding the following in the code where you try to access ExtendedWxPanel:

if instanceOfExctendedWxPanel:
then access it or methods of it.

Answered By: Werner

I had the same issue, I solved it by doing the following:

My code (which gave the error) was:

import wx
from pubsub import pub

class My_panel(wx.panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent)
        self.box = wx.BoxSizer(wx.VERTICAL)
        self.SetSizer(self.box)
        #
        pub.subscribe(self.do_something, 'Msg')

    def do_something(self):
        self.box.Layout()     

The above panel was in a wx.Notebook page. In my app the user has the possibility to add or delete page from this notebook.

When the pub.sendMessage(‘Msg’) code line was run after that the user deleted the notebook page containing this panel, I had the following error:

RuntimeError: wrapped C/C++ object of type BoxSizer has been deleted

which seems to be ~~ the new error type of ‘wx.PyDeadObjectError exception’ according to wxPython: https://wxpython.org/Phoenix/docs/html/MigrationGuide.html
What is explained in such documentation from wxPython is to use the nonzero() method which tests if the C++ object has been deleted.

Hence my working code is:

import wx
from pubsub import pub

class My_panel(wx.panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent)
        self.box = wx.BoxSizer(wx.VERTICAL)
        self.SetSizer(self.box)
        #
        pub.subscribe(self.do_something, 'Msg')

    def do_something(self):
        if self.__nonzero__():
            self.box.Layout()     
Answered By: roural