18

メインフレームの閉じるボタンをクリックすると、アプリケーションが閉じるはずです。しかし、私が実装した方法ではSegmentation fault、ボタンをクリックすると a で終了します。

後でディスクに保存する必要があるため、プログラムの安全なシャットダウンについて心配しています。

閉じるボタンを使用して 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 へのバインドがある場合、segfault が発生するまで無限ループに陥ります。EVT_CLOSE にバインドする主な理由は、閉じるイベントをキャッチして、ユーザーに情報を保存するように依頼できるようにするためです。それをしたい場合はself.Destroy、「self.Close」の代わりに使用して、そのイベントを発生させ続けないようにする必要があります。

既に述べたように、クローズ ハンドラーでは、スレッドを終了し、タスクバー アイコンを破棄し、開いているファイルを閉じるなどして、何もハングしないようにする必要があります。参照: http://wxpython.org/docs/api/wx.CloseEvent-class.html


OPの追加

私は2つの問題に直面していました。それらを見つけるのを手伝ってくれた3つの答えすべてに感謝します:

まず、実行中のスレッドを持つ属性があるため、フレームがself.Close()orに応答しません。このスレッドは最初に閉じる必要があります。self.Destroy()self.stuff

2 つ目は、self.Close()close イベントに応答し、呼び出されたときに無限再帰を引き起こすハンドラーです。これにより、ランタイム エラー (セグメンテーション違反、再帰の深さの超過) が発生します。self.Destroy()解決策は、代わりに使用することです。

于 2012-05-31T15:59:05.037 に答える
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ません。

于 2012-05-31T12:54:17.113 に答える
3

前の回答の 1 つは、アプリケーションを終了する前にユーザー情報を保存するために、Close() ではなく Destroy() を使用することについて説明しています。ユーザーに終了するかどうかを尋ねるサンプル コードを次に示します。彼らが肯定的に応答すると、フレームを「破棄」し、アプリケーションを終了します。

# 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 に答える