Вопрос по python – Как убить приложение WxPython, когда пользователь нажимает на закрытие фрейма

12

Приложение должно закрываться, когда я нажимаю кнопку закрытия основного кадра. Но, как я это реализовал, он выходит сSegmentation fault когда я нажимаю на кнопку.

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

Чтоproper non-violent way завершить 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   ответа
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 не называется.

Какой метод wxapp вы вызвали в обратном вызове? В примере вы звонитеwx.Destroy который кажется устаревшим. В моем примере вы можете выполнить сохранение в функции обратного вызова, когда функция возвращает True, программа будет закрыта сразу после сохранения.
Это хороший метод, его можно использовать для контроля закрытия любого окна в приложении.
Я использовал трюк с обратным вызовом, когда хотел, чтобы WxFrame вызывал метод его родительского WxApp. Пожалуйста, поправьте меня для лучшего способа. И меня беспокоит «ошибка сегментации» так как это может произойти до того, как у него появится шанс завершиться правильно (например, сохранить файл). Итак, вы предлагаете связать событие close с родительским приложением (app = wx.App(False)) и позволить событию закрытия ребенка распространяться вверх к нему? Jesvin Jose
10

Вот обычный способ закрытия кадра:

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's addition

Я столкнулся с двумя проблемами, я благодарюall three Ответы за помощь в их поиске:

Во-первых, кадр не реагирует наself.Close() или жеself.Destroy() потому что у него есть атрибутself.stuff у которого есть бегущая нить. Эта тема должна быть закрыта первой.

Во-вторых,self.Close() в обработчике, который отвечает на события закрытия и вызывает бесконечную рекурсию при вызове. Это вызывает ошибку времени выполнения (ошибка сегментации, превышена глубина рекурсии). Решение заключается в использованииself.Destroy() вместо.

1

Закрытие всех фреймов верхнего уровня в приложении должно завершить приложение без необходимости привязки к закрытию или чего-либо еще. Вы можете закрыть их самостоятельно.Close() если у вас есть несколько или некоторые из них скрыты.

Кроме того, если у вас есть TaskBarIcon, его нужно будет уничтожить до завершения работы приложения.

Я думаю, что ваша ошибка в сегменте может быть из-за другой причины, связанной с тем, как рамы разрушают и уничтожают их детей. Я попытаюсь пройтись по коду и выяснить, в какой момент происходит ошибка сегмента.

Я получаю исключениеpastebin.ca/2156533 когда я положил вself.Close() в_when_closed Jesvin Jose
Я полагаю, что это возможно потому, что вы связали событие close с вызовом close, которое вызывает одно и то же событие и непрерывно бесконечно вызывает close в цикле. Попробуйте открепить событие close, обработчик по умолчанию уже настроен на закрытие фрейма.
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()
работает для меня. Спасибо

Похожие вопросы