views:

75

answers:

3

When I try to call self.Close(True) in the top level Frame's EVT_CLOSE event handler, it raises a RuntimeError: maximum recursion depth exceeded. Here's the code:

from PicEvolve import PicEvolve
import wx

class PicEvolveFrame(wx.Frame):

    def __init__(self, parent, id=-1,title="",pos=wx.DefaultPosition,
         size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE,
         name="frame"):

        wx.Frame.__init__(self,parent,id,title,pos,size,style,name)

        self.panel = wx.ScrolledWindow(self)
        self.panel.SetScrollbars(1,1,600,400)

        statusBar = self.CreateStatusBar()

        menuBar = wx.MenuBar()
        menu1 = wx.Menu()
        m = menu1.Append(wx.NewId(), "&Initialize", "Initialize population with random images")
        menuBar.Append(menu1,"&Tools")
        self.Bind(wx.EVT_MENU,self.OnInit,m)
        self.Bind(wx.EVT_CLOSE,self.OnClose)

        self.SetMenuBar(menuBar)

    def OnInit(self, event):

        dlg = wx.TextEntryDialog(None,"Enter Population Size:","Population Size")
        popSize = 0
        if dlg.ShowModal() == wx.ID_OK:
            popSize = int(dlg.GetValue())
            self.pEvolver = PicEvolve(popSize,(200,200),True)

        box = wx.BoxSizer(wx.VERTICAL)

        filenames = []
        for i in range(popSize):
            filenames.append("img"+str(i)+".png")
        for fn in filenames:
            img = wx.Image(fn,wx.BITMAP_TYPE_ANY)
            box.Add(wx.StaticBitmap(self.panel,wx.ID_ANY,wx.BitmapFromImage(img)), 0,wx.BOTTOM)

        self.panel.SetSizer(box)

    def OnClose(self,event):

        self.Close(True)

class PicEvolveApp(wx.App):

    def OnInit(self):

        self.frame = PicEvolveFrame(parent=None,title="PicEvolve")
        self.frame.Show()
        self.SetTopWindow(self.frame)
        return True

if __name__ == "__main__":

    app = PicEvolveApp()
    app.MainLoop() 
A: 
def OnClose(self,event):
   event.Skip()

see http://wiki.wxpython.org/EventPropagation

iondiode
and by the way, close is already called on the frame when you close, so this callback is not necessary, unless you want to _do_ something during it.
iondiode
Hmmm.. I tried adding the Skip() and it's still returning the same error. The reason I put the callback there is because when I try to exit otherwise the window closes but the program is still running at the prompt.
Johnny
yeah, that's cuz what i put there was still wrong (doh). Actually if I comment out the import PicEvolve line and I remove the bind onclose and onClose callback, this code works fine. So maybe something in picEvolve module is running on init
iondiode
A: 

You don't need to catch EVT_CLOSE unless you want to do something special, like prompt the user to save. If you do that sort of thing, then call self.Destroy() instead. Right now you call OnClose when you hit the upper right "x", which then calls "Close", which fires the OnClose event....that's why you get the recursion error.

If you don't catch EVT_CLOSE and use self.Close() it should work. When it doesn't, then that usually means you have a timer, thread or hidden top-level window somewhere that also needs to be stopped or closed. I hope that made sense.

Mike Driscoll
How can I tell if something else is running that needs to be closed? Perhaps something from my PicEvolve class (which is used to to make pictures that are put in the panel) is hanging it up- how would I tell wxPython to stop it?
Johnny
If you have timers running, then in your OnClose event, you will need to stop them. You can use the timer's IsRunning() method to check them. For Top Level Windows, use wx.GetTopLevelWindows() to get a list of all of them and then iterate over them, closing or destroying them as needed.
Mike Driscoll
A: 

When you call window.Close it triggers EVT_CLOSE. Quoted from http://www.wxpython.org/docs/api/wx.CloseEvent-class.html

The handler function for EVT_CLOSE is called when the user has tried to close a a frame or dialog box using the window manager controls or the system menu. It can also be invoked by the application itself programmatically, for example by calling the wx.Window.Close function.

so obviously you will go into a infinite recursive loop. Instead in handler of EVT_CLOSE either destroy the window

def OnClose(self,event):
    self.Destroy()

or Skip the event

def OnClose(self,event):
    event.Skip(True)

or do not catch the EVT_CLOSE.

Edit: Btw why you want to catch the event, in other question you have put some comment, you should update the question accordingly, so that people can give better answers.

e.g when your program is still waiting on command prompt after close, it may mean you have some top level window still not closed.

To debug which one is still open, try this

for w in wx.GetTopLevelWindows():
    print w
Anurag Uniyal