2010-08-02 3 views
0

Когда я пытаюсь вызвать self.Close (True) в обработчике события EVT_CLOSE верхнего уровня Frame, он вызывает RuntimeError: превышена максимальная глубина рекурсии. Вот код:wxPython wx.Close create runtime error

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

ответ

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

см http://wiki.wxpython.org/EventPropagation

+1

и, кстати, близко уже называют на раме при закрытии, так что этот обратный вызов не нужен, если вы не хотите, чтобы _do_ что-то во время Это. – iondiode

+0

Хммм .. Я попробовал добавить Skip(), и он все равно возвращает ту же ошибку. Причина, по которой я поставил обратный вызов, состоит в том, что, когда я пытаюсь выйти, иначе окно закрывается, но программа все еще работает в подсказке. – Johnny

+0

Да, это потому, что я поставил там все еще неправильно (дох). На самом деле, если я прокомментирую строку импорта PicEvolve, и я удаляю call onclose и onClose, этот код работает нормально. Возможно, что-то в модуле picEvolve работает на init – iondiode

0

Вам не нужно, чтобы поймать EVT_CLOSE, если вы хотите сделать что-то особенное, как подсказывают пользователю сохранить. Если вы это сделаете, тогда вместо этого вызовите self.Destroy(). Прямо сейчас вы вызываете OnClose, когда вы нажимаете верхний правый «x», который затем вызывает «Close», который запускает событие OnClose .... вот почему вы получаете ошибку рекурсии.

Если вы не поймаете EVT_CLOSE и используете self.Close(), он должен работать. Когда это не так, это обычно означает, что у вас есть таймер, нить или скрытое окно верхнего уровня где-то, что также необходимо остановить или закрыть. Надеюсь, это имело смысл.

+0

Как я могу узнать, нужно ли что-то еще запускать, которое нужно закрыть? Возможно, что-то из моего класса PicEvolve (который используется для создания изображений, помещенных в панель), подвешивает его - как бы я сказал wxPython, чтобы остановить его? – Johnny

+0

Если у вас есть таймеры, то в вашем событии OnClose вам необходимо остановить их. Вы можете использовать метод IsRunning() таймера, чтобы проверить их. Для Windows верхнего уровня используйте wx.GetTopLevelWindows(), чтобы получить список всех из них, а затем перебрать их, закрыть или уничтожить их по мере необходимости. –

1

Когда вы вызываете window.Close, это вызывает EVT_CLOSE. Цитируется 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.

так очевидно, что вы будете идти в бесконечный рекурсивный цикл. Вместо этого в обработчике EVT_CLOSE либо уничтожить окно

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

или Пропустить это событие

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

или не поймать EVT_CLOSE.

Редактировать: Btw, почему вы хотите поймать событие, в другом вопросе вы поставили некоторый комментарий, вы должны соответствующим образом обновить вопрос, чтобы люди могли дать лучшие ответы.

например, когда ваша программа все еще ждет в командной строке после закрытия, это может означать, что окно верхнего уровня все еще не закрыто.

Для отладки, который один по-прежнему открыт, попробуйте это

for w in wx.GetTopLevelWindows(): 
    print w