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

Hi, My wx application work as expected but on exit dont destroy Timer object which calling StaticText. Object still running and doing console errors as in subject.
How to destroy wx application without errors?
So far, I’ve solved it with following code:

class MyFrame(wx.Frame):
    def __init__(self, *args, **kwds):
self.Bind(wx.EVT_CLOSE, self.OnClose)

def OnClose(self, event):
self.Destroy()

Regards,
Milos

If you assign the timer to an instance attribute (e.g. self.timer) try the following:

    def OnClose(self, event):
        if self.timer and self.timer.IsRunning():
            self.timer.Stop()
        self.Destroy()

since wx.Timer is a subclass of wx.Object one can destroy (timer.Destroy()) at any convenient moment (stay clean - stay well)

Timer Stop and self.Destroy() works.
Thanks

An EVT_CLOSE handler is not the right place to stop timers. EVT_WINDOW_DESTROY is.

To see why, try this:

import wx

class FrameCloseDemo(wx.Frame):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.Bind(wx.EVT_CLOSE, self.OnClose)

    def OnClose(self, event):
        event.Skip()
        print("EVT_CLOSE", self.GetTitle())

app = wx.App()
fr1 = FrameCloseDemo(None, -1, "First frame")
fr1.Show()
fr2 = FrameCloseDemo(fr1, -1, "Second frame")
fr2.Show()
app.MainLoop()

If you close the second frame first, then the first frame, then you get two messages:

EVT_CLOSE Second frame
EVT_CLOSE First frame

But if you close the first frame, then you only get one:

EVT_CLOSE First frame

So if you have a timer on the second frame, it doesn’t get an EVT_CLOSE event for that frame if the frame is destroyed by the parent, and in that case it will fail stop the timer, and you will get intermittent crashes because the expired timer tries to message a destroyed object.

Instead, use EVT_WINDOW_DESTROY:

class MyFrame(wx.Frame):
    ...
        self.Bind(wx.EVT_WINDOW_DESTROY, self._OnWindowDestroy)
    def _OnWindowDestroy(self, event):
        event.Skip()
        self.timer.Stop()

In this case timer running in thread

self._timer = threading.Timer(self.interval, self._run)

In that case I hope you realise that self._run can’t touch any of your wx.Window objects. That’s the advantage of wx.Timer: You can update the UI in the timer event, you can’t do that with threading.Timer.

wx.EVT_WINDOW_DESTROY is a command event and thus propagates upwards, so if the frame hangs somewhere in the middle of a hierarchy in which not all windows catch the destroy or, like here, skip it nicely then the identity must be checked (it’s the invers case, when the timer stops but the frame is still alive)

It does need to be stopped first however.

Thanks for the correction, Georg. I use the source parameter to Bind to filter out propagated events:

class MyFrame(wx.Frame):
    ...
        self.Bind(wx.EVT_WINDOW_DESTROY, self._OnWindowDestroy, self)
    def _OnWindowDestroy(self, event):
        event.Skip()
        self.timer.Stop()

@Robin, I’d like to add something about this to the Wiki, can I get editor access? I’m AndersMunchFlonidan there.

excuse me, but I think this Skip() is another oddity: on the one hand you restrict the source & on the other the event is sent on !?
the docu recommends to generally skip non-command events but even there I am usually selective (EVT_SIZE is an exception) :slightly_smiling_face:

they used to say the app has turned into a VW: it runs and runs and… but after that diesel gate and joining force with MS I expect any day my laptop to fume :joy:

Skip() is about not accidentally disabling some other functionality that relies on the event. It may be completely pointless here when you think it through, but I include it precisely so that I don’t have to think it through.

Well, that’s not quite my cup of tea & I hope the devs don’t fall victim to it :sneezing_face: (in quite a few places one would get the boot, but they are by far not the majority)
happy coding :see_no_evil:

P.S.:
I just came across a nice counter example: a plot of mine using lib.plot has a wx.Choice and if the event wx.EVT_CHOICE doesn’t get intercepted the plot flickers, not always but for some selections, a joy for when one has left the customer…