calling wx.CallAfter after wx.Frame.Destroy

From: Robin Dunn [mailto:robin@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?

  destroytype.process:
    exitFlag= True?

  process native event:
    eventtype.process

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()

* Invalid

ยทยทยท

-----Original Message-----