[wxPython-users] Application Not Terminating

OK, I spent some time looking at this morning and think I have a fix
that works for matplotlib wx API users as well as pylab users. For
the record, a little background.

The module matplotlib.backends.backend_wx contains all the classes to
enable matplotlib to be embedded in a wx application. There are two
modes this module is used in: application developers who want to
control the wx windows, panels, frames, etc, themselves, and pylab
users who want a matlab like environment in which all the figure
window, creation, etc, is managed for them.

To support the latter, all the matplotlib GUI backends are required to
define two functions

  new_figure_manager - creates a new wxFrame
  show - realizes/shows all frames

Jeremy O'Donoghue, who wrote the wx backend, and latter Matt Newville
who has been helping maintain it of late, tried putting the wxapp
instantiation in the show function, but this caused a segfault on some
platforms with some versions of wxpython (win32 with 2.4.x). We never
figured out the root cause of this since often times the person
developing/maintaining wx didn't have access to the buggy combination
of platform + version. So we left wxapp creation at the module level
which was ugly, hacky, and buggy, but at least it didn't seg fault.

Today I spent some time tracking down where and why the segfault was
occurring, and it was

  new_figure_manager -> FigureFrameWx -> wxPanel.__init__

The call to wxPanel.__init__ trigged the segfault.

It appears the cause of this problem is that the wxapp must be created
before the wxPanel is init'ed. The solution is to put the wxapp
creation in new_figure_manager, not show, so that the app will be
created before the wxpanel. This appears to work. Here is what I am
currently doing

wxapp = None # module level

def new_figure_manager(num, *args, **kwargs):
    global wxapp
    if wxapp is None:
        wxapp = wx.PySimpleApp()
        wxapp.SetExitOnFrameDelete(True)
    ...snipsnip...

def show():
    ...snipsnip...
    if show._needmain and not matplotlib.is_interactive():
        if wxapp is not None: wxapp.MainLoop()
        show._needmain = False

And this seems to work for pylab and wx apps. Since apps will never
call new_figure_manager or show, there should be no problem

If there is a better / more elegant / more wxlike way to do this, let
me know.

Thanks,
JDH

John,

It appears the cause of this problem is that the wxapp must be
created before the wxPanel is init'ed. The solution is to put
the wxapp creation in new_figure_manager, not show, so that
the app will be created before the wxpanel. This appears to
work. Here is what I am currently doing

Yep, I think this is exactly the problem (though I could never
reproduce it), and, like you say, creating wxapp in
new_figure_manager() sounds like the right solution to me. I
think this was part of the discussion with Marcin W. a month
ago, no?? Anyway, in backend_tkagg (the closest analogy I'm
familar with), Tk.Tk() is created in new_figure_manager. It
seems that with other windowing systems, it's ok to create the
mainApp (ie, who will run the event loop) if needed in show()???
Perhaps it would make sense to have this be more uniform across
the different backends?

Thanks,

--Matt

John Hunter wrote:

wxapp = None # module level

def new_figure_manager(num, *args, **kwargs):
    global wxapp
    if wxapp is None:
        wxapp = wx.PySimpleApp()
        wxapp.SetExitOnFrameDelete(True)
    ...snipsnip...

def show():
    ...snipsnip...
    if show._needmain and not matplotlib.is_interactive():
        if wxapp is not None: wxapp.MainLoop()
        show._needmain = False

And this seems to work for pylab and wx apps. Since apps will never
call new_figure_manager or show, there should be no problem

If there is a better / more elegant / more wxlike way to do this, let
me know.

You should check wx.GetApp() to ensure that the app hasn't already been created in some other module.

···

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