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

Aaron Brady castironpi at comcast.net
Mon Jan 21 20:46:05 PST 2008


> >>> 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.

However, if you block on MyCallAfterFunction's turn in the event queue, a
previously posted and sunk event, which blocks on the same synchronization
object, halts the queue, deadlocking it.

(*) 	def MyCallAfterFunction(frame):
 		if frame:
 			return frame.GetSomething()

> [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.




More information about the wxpython-users mailing list