问题描述
我在这里阅读了其他答案,但它们似乎都只是完全关闭应用程序,确保所有进程和框架等都在此过程中被销毁。我想做的有点不同。
我的应用程序由三个框架(StartFrame、ParaFrame、ResultFrame)以及一个用于存储和操作数据的自定义类组成。基础知识是: StartFrame 只是一些文本和一个“开始”按钮。 “Start”创建一个 ParaFrame 实例,隐藏 StartFrame,并显示 ParaFrame 实例。 Paraframe 有一堆小部件供用户选择文件以及如何分析它。输入所有字段后,弹出“分析”按钮,(单击时)实例化自定义DataHandler 类,根据用户选择设置其参数,调用分析数据、隐藏自身和实例化的DataHandler 方法显示结果框架。毫不奇怪,ResultsFrame 显示了分析结果。
我想添加一个“重新开始”控件,它将销毁所有内容(所有框架、面板、DataHandler 实例等)并显示一个新的 StartFrame 实例,或者以其他方式销毁所有内容除了已经实例化但隐藏的 StartFrame,再次显示该帧,但我不知所措。
一个简化的例子如下:
import wx
class StartFrame(wx.Frame):
"""App start frame"""
FRAME_MIN_SIZE = (900,600)
def __init__(self,parent):
wx.Frame.__init__(self,parent=parent,id=wx.ID_ANY,title="LOD Calculator",size=wx.Size(900,600),style=wx.CAPTION|wx.CLOSE_Box|wx.MINIMIZE_Box|wx.SYstem_MENU|wx.RESIZE_BORDER|wx.TAB_TRAVERSAL)
self.startpnl = wx.Panel(self)
self.startvsizer=wx.BoxSizer(wx.VERTICAL)
self.startbtnsizer=wx.BoxSizer(wx.HORIZONTAL)
self.btn = wx.Button(self.startpnl,wx.ID_ANY,"Start Analysis",\
size = (200,60))
self.btn.Bind(wx.EVT_BUTTON,self._OnStart)
self.startbtnsizer.AddStretchSpacer()
self.startbtnsizer.Add(self.btn,wx.CENTER)
self.startbtnsizer.AddStretchSpacer()
self.startvsizer.AddStretchSpacer()
self.startvsizer.Add(self.startbtnsizer,wx.SizerFlags().Expand().Border(wx.ALL,25))
self.startvsizer.AddStretchSpacer()
self.startpnl.SetSizerAndFit(self.startvsizer)
def _OnStart(self,event):
self.frm2 = ParaFrame(None)
self.Hide()
self.frm2.Show()
class ParaFrame(wx.Frame):
"""Data load frame"""
FRAME_MIN_SIZE = (950,800)
def __init__(self,size=wx.Size(950,800),style=wx.CAPTION|wx.CLOSE_Box|wx.MINIMIZE_Box|wx.SYstem_MENU|wx.RESIZE_BORDER|wx.TAB_TRAVERSAL)
self.mainpnl = wx.Panel(self)
self.mainsizer = wx.BoxSizer(wx.HORIZONTAL)
self.vsizer = wx.BoxSizer(wx.VERTICAL)
self.analyzebtn = wx.Button(self.mainpnl,u"Analyze",\
wx.DefaultPosition,wx.DefaultSize,0)
self.vsizer.AddStretchSpacer()
self.vsizer.Add(self.analyzebtn,wx.ALL,10)
self.vsizer.AddStretchSpacer()
self.mainsizer.AddStretchSpacer()
self.mainsizer.Add(self.vsizer,25))
self.mainsizer.AddStretchSpacer()
self.mainpnl.SetSizerAndFit(self.mainsizer)
self.analyzebtn.Bind(wx.EVT_BUTTON,self._analyze)
def _analyze(self,event):
dhandler = DataHandler(self)
dhandler.data = "a bunch"
dhandler.data2 = " of data"
dhandler.data3 = " goes here"
dhandler._analyzeData()
self.resfrm = ResultFrame(self,dhandler.data,dhandler.data2)
self.Hide()
self.resfrm.Show()
class DataHandler:
def __init__(self,parent):
self.data = ''
self.data2 = ''
self.data3 = ''
def _analyzeData(self):
anastr = self.data + self.data2 + " gets analyzed"
print(anastr)
class ResultFrame(wx.Frame):
def __init__(self,parent,targets,dftables):
super(ResultFrame,self).__init__(parent,title="results",size=(1535,935))
self.targets = targets
self.dftables = dftables
self.InitUI()
self.Layout()
def InitUI(self):
self.mainpnl = wx.Panel(self)
self.mainsizer = wx.BoxSizer(wx.HORIZONTAL)
self.vsizer = wx.BoxSizer(wx.VERTICAL)
self.restartbtn = wx.Button(self.mainpnl,u"Start Over",0)
self.vsizer.AddStretchSpacer()
self.vsizer.Add(self.restartbtn,25))
self.mainsizer.AddStretchSpacer()
self.mainpnl.SetSizerAndFit(self.mainsizer)
self.restartbtn.Bind(wx.EVT_BUTTON,self.OnRestart)
### this is where I try to destroy the ParaFrame instance and everything spawned by it,unsuccessfully
def OnRestart(self,event):
frm.frm2.Destroy()
frm.Show()
def main():
import wx.lib.mixins.inspection
app = wx.App()
frm = StartFrame(None)
frm.Show()
wx.lib.inspection.inspectionTool().Show(refreshTree=True)
app.MainLoop()
if __name__ == "__main__":
main()
如您所见,在 ResultFrame 中,我有一个“重新开始”按钮绑定到一个方法,在该方法中我尝试使用 {{1} },但得到一个错误:
frm.frm2.Destroy()
如果我将行更改为仅 Traceback (most recent call last):
File "C:\Python\Scripts\stackexchange code.py",line 102,in OnRestart
frm.frm2.Destroy()
NameError: name 'frm' is not defined
,我会收到相同的错误,但会显示 frm2.Destroy()
。
我在这里做错了什么,我该如何实现我的目标?我对 OOP 还是个新手,对 wxPython 还是很陌生,所以任何帮助都非常感谢。我想要的只是让该按钮销毁所有内容并再次显示/初始 StartFrame。谢谢:)
解决方法
只要创建没有父类的每个类,就可以在创建链中的下一帧后使用 self.Destroy()
,而不会破坏任何 children
。 (传递任何需要的数据作为父级以外的参数)
所以你的代码看起来像这样:
import wx
class StartFrame(wx.Frame):
"""App start frame"""
FRAME_MIN_SIZE = (900,600)
def __init__(self,parent):
wx.Frame.__init__(self,parent=parent,id=wx.ID_ANY,title="Load Calculator",size=wx.Size(900,600))
self.startpnl = wx.Panel(self)
self.startvsizer=wx.BoxSizer(wx.VERTICAL)
self.startbtnsizer=wx.BoxSizer(wx.HORIZONTAL)
self.btn = wx.Button(self.startpnl,wx.ID_ANY,"Start Analysis",\
size = (200,60))
self.btn.Bind(wx.EVT_BUTTON,self._OnStart)
self.startbtnsizer.AddStretchSpacer()
self.startbtnsizer.Add(self.btn,wx.CENTER)
self.startbtnsizer.AddStretchSpacer()
self.startvsizer.AddStretchSpacer()
self.startvsizer.Add(self.startbtnsizer,wx.SizerFlags().Expand().Border(wx.ALL,25))
self.startvsizer.AddStretchSpacer()
self.startpnl.SetSizerAndFit(self.startvsizer)
def _OnStart(self,event):
frm2 = ParaFrame(None)
frm2.Show()
self.Destroy()
class ParaFrame(wx.Frame):
"""Data load frame"""
FRAME_MIN_SIZE = (950,800)
def __init__(self,600))
self.mainpnl = wx.Panel(self)
self.mainsizer = wx.BoxSizer(wx.HORIZONTAL)
self.vsizer = wx.BoxSizer(wx.VERTICAL)
self.analyzebtn = wx.Button(self.mainpnl,u"Analyze",\
wx.DefaultPosition,wx.DefaultSize,0)
self.vsizer.AddStretchSpacer()
self.vsizer.Add(self.analyzebtn,wx.ALL,10)
self.vsizer.AddStretchSpacer()
self.mainsizer.AddStretchSpacer()
self.mainsizer.Add(self.vsizer,25))
self.mainsizer.AddStretchSpacer()
self.mainpnl.SetSizerAndFit(self.mainsizer)
self.analyzebtn.Bind(wx.EVT_BUTTON,self._analyze)
def _analyze(self,event):
dhandler = DataHandler(self)
dhandler.data = "a bunch"
dhandler.data2 = " of data"
dhandler.data3 = " goes here"
dhandler._analyzeData()
resfrm = ResultFrame(None,dhandler.data,dhandler.data2)
resfrm.Show()
self.Destroy()
class DataHandler:
def __init__(self,parent):
self.data = ''
self.data2 = ''
self.data3 = ''
def _analyzeData(self):
anastr = self.data + self.data2 + " gets analyzed"
print(anastr)
class ResultFrame(wx.Frame):
def __init__(self,parent,targets,dftables):
super(ResultFrame,self).__init__(parent,title="Results",size=(900,600))
self.targets = targets
self.dftables = dftables
self.InitUI()
self.Layout()
def InitUI(self):
self.mainpnl = wx.Panel(self)
self.mainsizer = wx.BoxSizer(wx.HORIZONTAL)
self.vsizer = wx.BoxSizer(wx.VERTICAL)
self.restartbtn = wx.Button(self.mainpnl,u"Start Over",0)
self.vsizer.AddStretchSpacer()
self.vsizer.Add(self.restartbtn,25))
self.mainsizer.AddStretchSpacer()
self.mainpnl.SetSizerAndFit(self.mainsizer)
self.restartbtn.Bind(wx.EVT_BUTTON,self.OnRestart)
### this is where I try to destroy the ParaFrame instance and everything spawned by it,unsuccessfully
def OnRestart(self,event):
frm = StartFrame(None)
frm.Show()
self.Destroy()
def main():
app = wx.App()
frm = StartFrame(None)
frm.Show()
app.MainLoop()
if __name__ == "__main__":
main()