wx.Dialog not reported as destroyed after '.Destroy()' is called

42 views
Skip to first unread message

Jasper Elzinga | Alexion Software

unread,
Jun 5, 2019, 10:49:25 AM6/5/19
to wxPython-dev
Hello,

I'm having trouble checking the destroyed state of wx.Dialogs. When I call '.Destroy()' and do a 'wx.Yield()' the dialog is not reported as destroyed:

dialog = wx.Dialog(self, -1, "")
result
= dialog.ShowModal()
dialog
.Destroy()

wx
.Yield()

print "wx version", wx.version()
print "is child", dialog in  self.GetChildren()
print "is being deleted", dialog.IsBeingDeleted()
print "not yet destroyed", bool(dialog)


Output:
wx version 3.0.2.0 msw (classic)
is child True
is being deleted False
not yet destroyed True

As far as I know this is the way it should be done according to a couple posts of people with similar questions.

I've tried many other things like multiple yields, time.sleep(), self.Refresh(), self.Update(). I've found one thing: if i create a new dialog and call '.ShowModal()', the first (destroyed) dialog is correctly reported as destroyed

I've attached my whole test script as an attachment. I've tested this in version 3.0.2.0 msw (the one we currently use) and in the latest version i get from 'pip install wxPython': 4.0.6 msw (phoenix) wxWidgets 3.0.5.

Any help would be greatly appreciated :)

Thanks,
Jasper
Alexion Software

dialogdestroytest.py
output.txt

Robin Dunn

unread,
Jun 5, 2019, 3:28:54 PM6/5/19
to wxPython-dev

On Wednesday, June 5, 2019 at 7:49:25 AM UTC-7, Jasper Elzinga | Alexion Software wrote:
Hello,

I'm having trouble checking the destroyed state of wx.Dialogs. When I call '.Destroy()' and do a 'wx.Yield()' the dialog is not reported as destroyed:

 
 
As far as I know this is the way it should be done according to a couple posts of people with similar questions.

I've tried many other things like multiple yields, time.sleep(), self.Refresh(), self.Update(). I've found one thing: if i create a new dialog and call '.ShowModal()', the first (destroyed) dialog is correctly reported as destroyed

When top-level windows are destroyed they are not killed immediately but are instead added to a list of windows to be destroyed later. What "later" actually means in this case is a little nebulous. I don't remember for sure, but I think it happens after EVT_IDLE events are sent and processed, or as part of the wx.App's EVT_IDLE handler, or something like that. Also, IIRC, the idle events are not sent during a wx.Yield, because the application is not idle at that point in time. (There are the pending events that need processed, if any, and then there is the code after the call to Yield that is waiting to run.

If you allow control to return to the event loop and then check the state of the dialog a little later, then most likely it has been destroyed by then.  It's not guaranteed however, because if the app is really busy then there may not have been a chance to process the idle events.
 
    def OnButton(self, event):
        dialog = wx.Dialog(self, -1, "ssss")
        result = dialog.ShowModal()
        dialog.Destroy()
        wx.Yield()
        wx.CallLater(100, self._later, dialog)

    def _later(self, dialog):
        print(self.GetChildren())
        print( "wx version", wx.version())
        print("is child", dialog in  self.GetChildren())
        print("is being deleted", dialog.IsBeingDeleted())
        print("not yet destroyed", bool(dialog))

--
Robin

Jasper Elzinga | Alexion Software

unread,
Jun 6, 2019, 8:19:31 AM6/6/19
to wxPython-dev
Thanks! This works.

However.. returning to the mainloop is not possible in our actual use case. We have a global dialog manager, and the code behind our button asks it for a dialog in a loop. The dialog manager has to know wether or not a dialog can be reused: if it's destroyed it can't be reused, but if it's for example hidden it can. This check currently fails. We can't allow the program to be accessable while the loop is running, thats why we use ShowModal and why wx.CallAfter is not possible (or at least i dont know how it would be possible using it).

Any suggestions? Perhaps there is a way to simulate an idle event? This way we can remain in our loop.

Ofcourse we can always do our own "destroyed" management with a 'self.destroyed' variable thats set to True by the 'Destroy' method in our dialog, but this feels wrong to me :)

Thanks,
Jasper

Mike Driscoll

unread,
Jun 6, 2019, 9:12:16 AM6/6/19
to wxPyth...@googlegroups.com
You can send your own idle events: https://wxpython.org/Phoenix/docs/html/wx.IdleEvent.html 

Just read the documentation carefully as it can increase system load.

Mike

Eric Fahlgren

unread,
Jun 6, 2019, 11:17:36 AM6/6/19
to wxPyth...@googlegroups.com
Is sending idle events sufficient?  I think you have to flush the event queue for the object before it is destroyed (i.e., run its event loop) or else you'll get crashes later when those events are routed to the now-destroyed widget.  Something like

>>> for event in ???:
>>>     widget.GetEventHandler().ProcessEvent(event)

or whatever???


--
You received this message because you are subscribed to the Google Groups "wxPython-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to wxPython-dev...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/wxPython-dev/CAO4gEAs5tDD4MSAS3RWAZ2h0-f6KXeqxdLsYQoM9xuHmh4d-PA%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.
Reply all
Reply to author
Forward
0 new messages