of course, this Bind will not help much if the owners of the timers are casually changed !
(in the example it’s a difference of closing tic or tac first, thanks to the OS)
import wx
class Frame(wx.Frame):
def __init__(self, frm, *args, **kwargs):
super().__init__(*args, **kwargs)
self.frm = frm
self.timer = wx.Timer()
print(f'{self.Title} timer is {id(self.timer)}')
self.timer.SetOwner(self)
self.timer.Start(1000)
self.Bind(wx.EVT_TIMER, self.OnTimer)
self.Bind(wx.EVT_WINDOW_DESTROY,
lambda _: self.timer.Destroy())
self.Show()
def OnTimer(self, evt):
print(f'{evt.GetEventObject().Title} from timer {id(evt.GetTimer())}')
if self.frm:
self.timer.SetOwner(self.frm)
print(f'timer owner of {self.Title} switched to {self.frm.Title}')
if __name__ == "__main__":
app = wx.App()
frm = Frame(None, None, title='tic')
Frame(frm, None, title='tac')
app.MainLoop()
My code would only crash about 1/4 times. Like it was a race condition to see what shutdown first. It was a giant pain in the ass to debug because seeing what crashes the gui didn’t really have any debug tools. I had to bisect through the git changes to find a timer was added that looked perfectly harmless. And then I had to change the timer up to one not associated with the gui.
This issue is still an issue. And it’s really hard to trackdown when it crops up.
Sometimes it takes a while to understand your intent, sorry … and yes, after the window is destroyed (at the time the EVT_WINDOW_DESTROY handler is called), the added objects remain (even after the mainloop is terminated). It’s not magic at all.
well, this wasn’t really meant for you (I like your example)
but as you may well see from the discussion timers aren’t intuitive as other wx objects and on top of that, of course, garbage collection gives all that a real downside boost (one man’s meat is another man’s poison)
well, it’s simply the additional references which don’t go well with the wind down of the MainLoop (if you have only a single window it works), but I think that can always be avoided
more interesting will be to handle an additional Python async loop