这是我生命中的祸根:
追踪(最近一次通话): OnDestroy中的文件“C:\ Users \ User \ Documents \ PYTHON \ GAME FILES \ simple.py”,第18行 self.Destroy() 文件“C:\ Python26 \ lib \ site-packages \ wx-2.8-msw-ansi \ wx_core.py”,第14610行, getattr _ 引发PyDeadObjectError(self.attrStr%self._name) wx._core.PyDeadObjectError:MyPanels对象的C ++部分已被删除,属性>不再允许访问。
我的目标:拥有两个面板,左侧面板通过按钮杀死并“重新创建”右侧面板/相同副本,模拟用户如何在左侧面板中选择他们想要看到的内容和有正确的面板显示这个。这就是我在更复杂的程序中尝试做的事情,但那是失败的,所以我试图在这里学习如何销毁和重新创建一个空白面板。仍然是相同的TERRIFYING错误。
代码:
import wx
import sys
import traceback
def show_error():
message = ''.join(traceback.format_exception(*sys.exc_info()))
dialog = wx.MessageDialog(None, message, 'Error!', wx.OK|wx.ICON_ERROR)
dialog.ShowModal()
class MyPanels(wx.Panel):
def __init__(self, parent, id):
wx.Panel.__init__(self, parent)
self.parent = parent
def OnDestroy(self, event):
self.Destroy()
def OnTest(self, event):
print "Hello"
class MyFrame(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title, size=(1000, 480))
self.parent = parent
self.panel = MyPanels(self, -1)
self.panel.SetBackgroundColour("grey")
self.panel.leftpanel = MyPanels(self.panel, 1)
self.panel.rightpanel = MyPanels(self.panel, 1)
self.panel.leftpanel.SetBackgroundColour("red")
self.panel.rightpanel.SetBackgroundColour("green")
self.panel.basicsizer = wx.BoxSizer(wx.HORIZONTAL)
self.panel.basicsizer.Add(self.panel.leftpanel, 1, wx.EXPAND)
self.panel.basicsizer.Add(self.panel.rightpanel, 1, wx.EXPAND)
self.panel.SetSizer(self.panel.basicsizer)
button = wx.Button(self.panel.leftpanel, 1, 'DIE DIE DIE', (50, 130))
buttonres = wx.Button(self.panel.leftpanel, 2, 'Resurrect', (50, 230))
buttonextra = wx.Button(self.panel.leftpanel, 3, 'Test', (50, 330))
self.Bind(wx.EVT_BUTTON, self.panel.rightpanel.OnDestroy, id = 1)
self.Bind(wx.EVT_BUTTON, self.CreateNewPanel, id = 2)
self.Bind(wx.EVT_BUTTON, self.panel.rightpanel.OnTest, id = 3)
def CreateNewPanel(self, event):
self.panel.rightpanel = MyPanels(self.panel, 1)
self.panel.rightpanel.SetBackgroundColour("green")
self.panel.basicsizer.Add(self.panel.rightpanel, 1, wx.EXPAND)
self.panel.SetSizer(self.panel.basicsizer)
self.panel.rightpanel.Refresh()
self.panel.leftpanel.Refresh()
self.panel.leftpanel.Layout()
self.panel.leftpanel.Update()
self.panel.Layout()
self.Update()
self.Show(True)
self.Centre()
def main():
app = wx.App()
try:
frame = MyFrame(None, -1, 'Die.py')
frame.Show()
app.MainLoop()
except:
show_error()
if __name__ == '__main__':
main()
基本上,似乎我(最终)让Resurrect Button工作,至少在'new'面板填充了适当的空间。但是,如果我再次尝试杀死它,就会出现可怕的错误。
我一直在研究错误信息,似乎我得到了这个,因为self.Destroy()破坏了程序中某些东西仍然需要的东西。我发现这很难理解,因为我以为我正在创建一个完美相同的副本,同名。
我认为它唯一可能是杀戮按钮本身。就好像它需要原始的右面板再次销毁一样,它被锁定在它唯一的类引用中,而不是它的右面板名称。我添加了第三个按钮来测试它。第三个按钮具有几乎相同的代码,它只是调用MyPanels类中的不同方法。并且......它仍然在杀戮和复活之后起作用。但再次按下Kill不起作用。它们之间的唯一区别是OnDestroy方法使用'self'。
不知何故,我想我必须停止Kill按钮的事件将其自身绑定到原始右侧面板的“self”。我完全迷失了。我已经无可救药地告诉左侧面板刷新/更新自己。没有。过去两天都试图解决这个问题。我是python和wxpython的新手,我完全沉浸在这里,但是,请帮助我。
编辑 -
好吧,刚才有一个迷你脑波。我认为一旦事件与Bind命令绑定,它将永远绑定到该窗口小部件,除非它被更改。这就是为什么它仍然坚持死板。 所以,如果我解除绑定然后重新绑定它,那是解决方案吗?我已将按钮名称更改为self.button。然后在def CreateNewPanel()方法中,我将一个Unbind命令放入...然后立即将复制粘贴到Bind命令。它似乎现在正在工作!!!!
但......有人可以告诉我: 1)这是正确的解决方案,还是我提出的一些繁琐的解决方法 2)为什么我打电话时为什么整个画面在屏幕上跳了半英寸 self.panel.rightpanel.Refresh()?
** 编辑 -
现在我似乎能够根据LeftPanel的按钮销毁和重新创建RightPanel,我试图在复杂的程序上管理它。 复杂程序旨在根据用户对LeftPanel 上的名称列表控件的选择,显示RightPanel中字符的信息(生物+图片)。
所以它与此非常相似:它没有空的RightPanel,而是有大量的小部件。
它在某种程度上确实有效。如果我单击以查看Character X,RightPanel会自行销毁,然后使用Character Y的小部件重新创建自己。好极了。但它也暂时在RightPanel的左上角闪烁一个小方块,它清楚地包含所有小部件的副本。
这个方块几乎立即消失,但每次点击更改RightPanel的内容时它都清晰可见。这很难看。我只是无法摆脱它!我试过点到.Layout()到处都是,不管怎样。无法解决为什么会出现然后消失!这是一个我无法摆脱的程序延迟吗?或者我正在用sizer做出一些错误?必须强调 - 小部件按照我的意图完美布局......所以尺寸确定工作正常......对吧? **
答案 0 :(得分:3)
我认为这里的问题是你以一种非常奇怪的方式将所有东西捆绑在一起。您通常不会通过执行MyPanel.panel = wx.Panel()创建嵌套面板。相反,您可以按照创建任何面板的正常方式创建它们:
panelOne = wx.Panel(self)
panelTwo = wx.Panel(self)
panelThree = MyPanels(parent, id)
我也会像你一样避免创建sizer。我使用像
这样的东西mySizer = wx.BoxSizer()
我最终清理掉了一堆奇怪的垃圾以使其发挥作用。我没有看到破坏面板的理由,所以我只是隐藏了它:
import wx
import sys
import traceback
def show_error():
message = ''.join(traceback.format_exception(*sys.exc_info()))
dialog = wx.MessageDialog(None, message, 'Error!', wx.OK|wx.ICON_ERROR)
dialog.ShowModal()
class MyPanels(wx.Panel):
def __init__(self, parent, id):
wx.Panel.__init__(self, parent)
self.parent = parent
class MyFrame(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title, size=(1000, 480))
self.parent = parent
self.panel = wx.Panel(self, -1)
self.panel.SetBackgroundColour("grey")
self.leftpanel = MyPanels(self.panel, 1)
self.rightpanel = MyPanels(self.panel, 1)
self.leftpanel.SetBackgroundColour("red")
self.rightpanel.SetBackgroundColour("green")
self.basicsizer = wx.BoxSizer(wx.HORIZONTAL)
self.basicsizer.Add(self.leftpanel, 1, wx.EXPAND)
self.basicsizer.Add(self.rightpanel, 1, wx.EXPAND)
self.panel.SetSizer(self.basicsizer)
button = wx.Button(self.leftpanel, 1, 'DIE DIE DIE', (50, 130))
buttonres = wx.Button(self.leftpanel, 2, 'Resurrect', (50, 230))
buttonextra = wx.Button(self.leftpanel, 3, 'Test', (50, 330))
self.Bind(wx.EVT_BUTTON, self.destroyPanel, button)
self.Bind(wx.EVT_BUTTON, self.CreateNewPanel, buttonres)
def CreateNewPanel(self, event):
self.rightpanel = MyPanels(self.panel, 1)
self.rightpanel.SetBackgroundColour("green")
self.basicsizer.Add(self.rightpanel, 1, wx.EXPAND)
self.panel.Layout()
self.Show(True)
self.Centre()
def destroyPanel(self, event):
self.rightpanel.Hide()
self.panel.Layout()
def main():
app = wx.App()
try:
frame = MyFrame(None, -1, 'Die.py')
frame.Show()
app.MainLoop()
except:
show_error()
if __name__ == '__main__':
main()
这个练习让我想起了几年前我的面板切换文章:http://www.blog.pythonlibrary.org/2010/06/16/wxpython-how-to-switch-between-panels/
也许这对你也有帮助。
答案 1 :(得分:1)
是的,这是正确的解决方案,尽管更多的pythonic方法是在销毁面板的同时取消绑定Die
按钮,这样多次按下该按钮就不会抛出一个例外。这样的事情应该做:
self.Bind(wx.EVT_BUTTON, self.OnPanelDestroy, id = 1)
def OnPanelDestroy(self, event):
self.Unbind(wx.EVT_BUTTON, id = 1)
self.panel.rightpanel.OnDestroy(event)
def CreateNewPanel(self, event):
self.panel.rightpanel = MyPanels(self.panel, 1)
self.panel.rightpanel.SetBackgroundColour("green")
self.Bind(wx.EVT_BUTTON, self.OnPanelDestroy, id = 1)
如果我理解正确,那是因为调用了self.Centre()
而不是self.panel.rightpanel.Refresh()
。如果你将它评论出来,框架就不会在屏幕上居中,而是保持不变。