Events firing after object destroyed

I've attached/appended a short program that shows wx.EVT_TREE_SEL_CHANGED events being fired AFTER the containing dialog has been destroyed. I can fix it by unbinding before the dialog is destroyed, but I figured I should report this. Note that it doesn't happen if Dlg() is the topmost window, only if it is called from within another dialog.

Phil Mayes

import wx

hint = """
1. Click the "Browse" button.
2. Select a Drive.
3. Click "OK".
4. OnDir() is called after self.gdc is destroyed.
If self.gdc.GetPath() is called, nasty things happen.
"""

class Dlg(wx.Dialog):
     def __init__(self, start=''):
         wx.Dialog.__init__(self, None, -1, "Select a folder", size=(700,500), style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER)
         sizer = wx.BoxSizer(wx.VERTICAL)
         self.gdc = wx.GenericDirCtrl(self, -1, dir=start, size=(200,225), style=wx.DIRCTRL_DIR_ONLY)
         sizer.Add(self.gdc, 1, wx.EXPAND|wx.ALL, 5)
         okay = wx.Button(self, wx.ID_OK)
         sizer.Add(okay, 0, wx.ALL, 5)
         self.SetSizer(sizer)
         sizer.Fit(self)

         self.tree = self.gdc.GetTreeCtrl()
         self.tree.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnDir)

     def OnDir(self, evt):
         print 'OnDir',evt
## xxx = self.gdc.GetPath() # crashes
## print 'xxx',xxx

class OuterDlg(wx.Dialog):
     def __init__(self):
         wx.Dialog.__init__(self, None, -1, "Outer dialog")
         sizer = wx.BoxSizer(wx.VERTICAL)
         sizer.Add(wx.StaticText(self, -1, hint), 0, wx.ALL, 5)
         fileButton = wx.Button(self, -1, "&Browse...")
         fileButton.Bind(wx.EVT_BUTTON, self.OnBrowse)
         sizer.Add(fileButton, 0, wx.ALL, 5)
         self.SetSizer(sizer)
         sizer.Fit(self)

     def OnBrowse(self, evt):
         dlg = Dlg()
         dlg.ShowModal()
         print 'before destroy'
         dlg.Destroy()
         print 'after destroy'

if __name__=='__main__':
     app = wx.PySimpleApp()
     dlg = OuterDlg() # if this is Dlg(), problem vanishes!
     dlg.ShowModal()
     dlg.Destroy()

crash.py (1.58 KB)

Phil Mayes wrote:

I've attached/appended a short program that shows wx.EVT_TREE_SEL_CHANGED events being fired AFTER the containing dialog has been destroyed. I can fix it by unbinding before the dialog is destroyed, but I figured I should report this. Note that it doesn't happen if Dlg() is the topmost window, only if it is called from within another dialog.

Top level windows are not actually destroyed when Destroy is called, it is just added to a list which is processed in idle time. This is done so that pending events can still be processed.

In this case however the EVT_TREE_SEL_CHANGED events are happening when items are being removed from the tree, forcing the selection to move to an undeleted item. So in this case it is proper to be able to detect that a shutdown/destroy is in progress and not do anything unsafe if so. You can use self.IsBeingDeleted() to tell if the dialog is in the process of being destroyed before trying to use it.

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!