[wxPython-users] calling wx.CallAfter after wx.Frame.Destroy

Robin Dunn robin at alldunn.com
Mon Jan 21 18:42:33 PST 2008


Aaron Brady wrote:
>> -----Original Message-----
>> From: Robin Dunn [mailto:robin at alldunn.com]
>> Sent: Monday, January 21, 2008 7:37 PM
>>> Will MainLoop exit if other events are added to the event queue after or
>>> during delete, or will it address those first?  IOW in other words, when
>>> does it return?
>> IIRC, it's a little different depending on how the platform specific
>> event loops are handled, but in general when a TLW is finally destroyed
>> wx checks if is was the last one in the top level window list, if so
>> then it sets a flag that is checked in the next iteration of the main
>> loop.
>>
>>> If one calls CallAfter while or after the pending delete queue is being
>>> processed, are further references are invalid?
>>
>> The order of execution is essentially something like this pseudo-code:
>>
>> while not exitFlag:
>> 	while native events waiting:
>> 		get next native event
>> 		process native event
>>
>> 	process posted events
>> 	send idle event
>> 	delete destroyed TLWs
>>
>>
>> The wx.CallAfter's are implemented by posting events, so they are called
>> before the pending delete queue is checked.  So yes it is possible that
>> a TLW or widget used by a CallAfter function is not valid at the time
>> the function is called, however if that was the last TLW and the main
>> loop is exiting then it is probably not likely.
> 
> Fine.  Where is exitFlag set?

In the top-level window destructor if that TLW is the last one.  Or from 
the wx.App's ExitMainLoop method.

>> If in doubt it is easy
>> to check.  When a C++ widget object is deleted and it knows what it's
>> Python proxy object is, andif there is more than one reference to that
>> proxy then wxPython will replace the __class__ of that proxy object with
>> one that raises an exception if you try to evaluate any of it's
>> attributes (the PyDeadObjectError exception) and it also has a
>> __nonzero__ method that returns False.  That means that you can use a
>> simple if test to see if the widget is still alive, like this:
>>
>> 	def MyCallAfterFunction(frame):
>> 		if frame:
>> 			frame.DoSomething()
> 
> It's only if it might be running in a second thread that awry might it go;
> if between 'if frame' and 'frame.What', MainLoop destroys, or worse, begins
> to destroy frame.
> 
> (*)	def MyCallAfterFunction(frame):
> 		if frame:
> 			<thread turnover to MainLoop destroys frame>
> 			frame.DoSomething()

But the point is that if you are calling this function via wx.CallAfter 
then it is impossible for the frame to be destroyed after the if and 
before the DoSomething(), because this is already executing in the GUI 
thread via a posted event, and so it is impossible[1] for this thread to 
jump back into the main loop and do the final destruction of the frame 
until after this function has returned.

[1] Except, of course, if you use one of the wx Yield functions here, 
which is one of the reasons that it is recommended that they not be used 
unless absolutely necessary.

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




More information about the wxpython-users mailing list