如何在用户单击框架关闭时终止WxPython应用程序

时间:2012-05-31 11:59:29

标签: python wxpython

当我单击主框架的关闭按钮时,应用程序应该关闭。但是我实现它的方式,当我点击按钮时,它会以Segmentation fault退出。

我担心安全关闭程序,因为我需要稍后将内容保存到磁盘上。

通过关闭按钮终止WxPython应用程序的正确的非暴力方式是什么?


这是我实施的程序的“主要”循环:

if __name__ == "__main__":
    app = wx.App(False)
    mf = MainFrame(None, title='Spectrum Checker') #subclasses frame
    mf.register_close_callback( app.Destroy) #what is the apt func?
    app.MainLoop()

以下是如何在MainFrame

中实现回调
def __init__(self, parent, title):
    ...
    self.Bind(wx.EVT_CLOSE, self._when_closed)

...

def _when_closed(self, event):
if self.__close_callback__:
    self.__close_callback__()

4 个答案:

答案 0 :(得分:13)

这是关闭框架的常规方法:

import wx

########################################################################
class MyFrame(wx.Frame):
    """"""

    #----------------------------------------------------------------------
    def __init__(self):
        """Constructor"""
        wx.Frame.__init__(self, None, title="Close Me")
        panel = wx.Panel(self)

        closeBtn = wx.Button(panel, label="Close")
        closeBtn.Bind(wx.EVT_BUTTON, self.onClose)

    #----------------------------------------------------------------------
    def onClose(self, event):
        """"""
        self.Close()

if __name__ == "__main__":
    app = wx.App(False)
    frame = MyFrame()
    frame.Show()
    app.MainLoop()

现在,如果你绑定了wx.EVT_CLOSE,那么你将陷入无限循环,直到遇到段错误。绑定到EVT_CLOSE的主要原因是您可以捕获close事件并要求用户保存其信息。如果你想这样做,那么你需要使用self.Destroy而不是" self.Close"所以你不要继续发射这个事件。

正如已经提到的,在你的关闭处理程序中,你需要确保你结束线程,销毁任务栏图标,关闭打开文件等等,这样就没有任何问题。另见:http://wxpython.org/docs/api/wx.CloseEvent-class.html


OP的补充

我面临两个问题,我感谢所有三个答案帮助我找到它们:

首先,框架不响应self.Close()self.Destroy(),因为它有一个具有正在运行的线程的属性self.stuff。必须先关闭此主题。

其次,self.Close()在处理程序中响应close事件并在调用时导致无限递归。这会导致运行时错误(分段错误,超出递归深度)。解决方案是使用self.Destroy()代替。

答案 1 :(得分:6)

我不确定为什么你需要回调来关闭应用程序?如果未将任何内容绑定到MainFrame,则单击关闭按钮时应自动关闭应用程序。除非你有一些其他线程运行阻止进程结束。如果您仍希望绑定到close事件并在关闭之前执行某些操作,则应在事件处理程序中使用event.Skip(),如果您仍想关闭窗口。否则,事件不会进一步传播,并且不会执行默认处理程序。一个例子:

import wx

class MainFrame(wx.Frame):
    def __init__(self, *args, **kwargs):
        wx.Frame.__init__(self, *args, **kwargs)
        self.__close_callback = None
        self.Bind(wx.EVT_CLOSE, self._when_closed)

    def register_close_callback(self, callback):
        self.__close_callback = callback

    def _when_closed(self, event):
        doClose = True if not self.__close_callback else self.__close_callback()
        if doClose:
            event.Skip()

if __name__ == "__main__":
    app = wx.App(False)
    mf = MainFrame(None, title='Test')
    mf.Show()
    mf.register_close_callback(lambda: True)
    app.MainLoop()

执行代码并单击“关闭”时,应用程序将关闭。当您将回调函数更改为lambda: False时,由于未调用Skip,窗口将不会关闭。

答案 2 :(得分:2)

之前的一个答案讨论了使用Destroy()而不是Close()以便在退出应用程序之前保存用户信息。以下是一些示例代码,询问用户是否打算退出。如果他们回答是肯定的,它会“破坏”框架并退出申请。

# Bind our events from our menu item and from the close dialog 'x' on the frame
def SetupEvents(self):
    self.Bind(wx.EVT_CLOSE, self.OnCloseFrame)
    self.Bind(wx.EVT_MENU, self.OnCloseFrame, self.fileMenuExitItem)


# Destroys the main frame which quits the wxPython application
def OnExitApp(self, event):
    self.Destroy()


# Makes sure the user was intending to quit the application
def OnCloseFrame(self, event):
    dialog = wx.MessageDialog(self, message = "Are you sure you want to quit?", caption = "Caption", style = wx.YES_NO, pos = wx.DefaultPosition)
    response = dialog.ShowModal()

    if (response == wx.ID_YES):
        self.OnExitApp(event)
    else:
        event.StopPropagation()

答案 3 :(得分:1)

关闭应用中的所有顶级框架应该结束应用程序而无需绑定到关闭或其他任何内容。如果您有几个或一些隐藏的,可以使用.Close()自行关闭它们。

此外,如果你有一个TaskBarIcon,那么在应用程序结束之前需要将其销毁。

我认为你的段错可能是因为另一个原因,与帧如何拆除并摧毁他们的孩子有关。我会尝试单步执行代码,找出seg故障发生的时间点。