Вопрос по python – Как убить приложение WxPython, когда пользователь нажимает на закрытие фрейма
Приложение должно закрываться, когда я нажимаю кнопку закрытия основного кадра. Но, как я это реализовал, он выходит с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__()
Я не уверен, зачем вам нужен обратный звонок, чтобы закрыть приложение? Если вы ничего не привязываете к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
не называется.
wx.Destroy
который кажется устаревшим. В моем примере вы можете выполнить сохранение в функции обратного вызова, когда функция возвращает True, программа будет закрыта сразу после сохранения.
app = wx.App(False)
) и позволить событию закрытия ребенка распространяться вверх к нему?
Вот обычный способ закрытия кадра:
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()
вместо.
Закрытие всех фреймов верхнего уровня в приложении должно завершить приложение без необходимости привязки к закрытию или чего-либо еще. Вы можете закрыть их самостоятельно.Close()
если у вас есть несколько или некоторые из них скрыты.
Кроме того, если у вас есть TaskBarIcon, его нужно будет уничтожить до завершения работы приложения.
Я думаю, что ваша ошибка в сегменте может быть из-за другой причины, связанной с тем, как рамы разрушают и уничтожают их детей. Я попытаюсь пройтись по коду и выяснить, в какой момент происходит ошибка сегмента.
self.Close()
в_when_closed
В одном из предыдущих ответов обсуждается использование 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()