18

当我单击主框架的关闭按钮时,应用程序应该关闭。但是我实现它的方式是,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

4 回答 4

19

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

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 的主要原因是您可以捕获关闭事件并要求用户保存他们的信息。如果你想这样做,那么你需要使用self.Destroy而不是“self.Close”,这样你就不会继续触发那个事件。

正如已经提到的,在您的关闭处理程序中,您需要确保结束线程、销毁任务栏图标、关闭打开的文件等,以免挂起。另见:http ://wxpython.org/docs/api/wx.CloseEvent-class.html


OP的补充

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

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

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

于 2012-05-31T15:59:05.037 回答
6

我不确定你为什么需要回调来关闭应用程序?如果你没有绑定任何东西到MainFrame,当你点击关闭按钮时应用程序应该会自动关闭。除非您有其他线程正在运行,这会阻止进程结束。如果您仍想绑定到关闭事件并在关闭之前执行某些操作,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不会被调用。

于 2012-05-31T12:54:17.113 回答
3

先前的答案之一讨论了使用 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()
于 2014-05-02T17:36:50.567 回答
1

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

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

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

于 2012-05-31T13:17:54.770 回答