wxPython+;weakref proxy=关闭wx.Frame不会产生任何结果

wxPython+;weakref proxy=关闭wx.Frame不会产生任何结果,python,wxpython,weak-references,Python,Wxpython,Weak References,我目前正在用wxWigets制作一个Python应用程序,它有两个窗口。第一个窗口是主“控制器”窗口,第二个窗口是数据显示窗口 我想有一些机制,让第一个窗口知道第二个窗口是在哪里生成的,如果是,它是否被用户关闭。我考虑过使用Python的weakref.proxy(),因为基于我对该语言的一点了解,似乎如果对象被关闭/销毁/解除分配/GC'ed,任何调用我的代理的尝试都会返回一个None值,可以方便地使用Python的is None/is not None运算符检查 只要生成一次窗口,代理就会按

我目前正在用wxWigets制作一个Python应用程序,它有两个窗口。第一个窗口是主“控制器”窗口,第二个窗口是数据显示窗口

我想有一些机制,让第一个窗口知道第二个窗口是在哪里生成的,如果是,它是否被用户关闭。我考虑过使用Python的weakref.proxy(),因为基于我对该语言的一点了解,似乎如果对象被关闭/销毁/解除分配/GC'ed,任何调用我的代理的尝试都会返回一个
None
值,可以方便地使用Python的
is None
/
is not None
运算符检查

只要生成一次窗口,代理就会按预期工作,如果尚未生成窗口,则返回
None
,否则返回对对象的引用。但一旦我关闭辅助窗口,代理对象将不会像预期的那样恢复为
None
,我的应用程序将因
ReferenceError而崩溃:弱引用对象不再存在

我记得以前尝试过解决这个问题,我发现最有效的解决方案是对照内部wx类检查对象的类名,如:

if windowObject.__class__.__name__ is not "_wxPyDeadObject": #do stuff
然而,对我来说,这似乎是一个非常老套的解决方案,我想知道除了上面提到的以外,还有没有更好的办法。下面是一些复制我的这个问题的基本代码

import wx
import weakref


class SillyWindow(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, parent=None, title="Spawned Window")
        self.Show()


class ExWindow(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, parent=None, title="Main Window")

        self.panel = wx.Panel(self)
        self.button = wx.Button(self.panel, label="Spawn window!")
        self.Bind(wx.EVT_BUTTON, self.spawn, self.button)
        self.txt = wx.TextCtrl(self.panel, pos=(0,100))

        self.wind = None

        self.timer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.update, self.timer)
        self.timer.Start(50)
        self.Show()

    def spawn(self,event):
        if self.wind is None:  # Preventing multiple spawning windows
            self.wind = weakref.proxy(SillyWindow())

    def update(self,event):
        if self.wind is not None:
            self.txt.SetValue(str(self.wind))
        else:
            self.txt.SetValue("None")


app = wx.App(False)
frame = ExWindow()
app.MainLoop()

如您所见,当wx widget对象被销毁时,Python代理对象的类将被替换为一个类,当您尝试使用它时,该类将对其进行更改以引发异常。它还有一个
\uuuuu nonzero\uuuuu
方法,因此您可以执行类似的操作,而不是深入挖掘对象的内部以查找其类名:

if not windowObject:
    # it has been destroyed already
    return
要记住的另一件事是,顶级窗口在关闭或调用其
Destroy
方法时不会被销毁。相反,它们被添加到一个挂起的删除列表中,一旦没有更多的挂起事件,该列表就会被处理。您可以通过调用帧的
IsBeingDeleted
方法来测试该情况(已关闭但尚未销毁)。此外,UI对象的C++部分也保留了自己对Python对象的引用,尽管在C++对象被销毁时,这将是递减的。因此,这些事情中的一些或全部可能会干扰你的weafref方法。就我个人而言,我只会像上面那样使用
if
语句。短。好极了。简单


另外,我在这里提到的一些细节是针对wxPython Classic的,在凤凰城的处理方式不同。但是,像上面那样使用
if
语句仍然有效。

正如您所看到的,当wx小部件对象被销毁时,Python代理对象的类将被替换为一个更改它的类,以便在您尝试使用它时引发异常。它还有一个
\uuuuu nonzero\uuuuu
方法,因此您可以执行类似的操作,而不是深入挖掘对象的内部以查找其类名:

if not windowObject:
    # it has been destroyed already
    return
要记住的另一件事是,顶级窗口在关闭或调用其
Destroy
方法时不会被销毁。相反,它们被添加到一个挂起的删除列表中,一旦没有更多的挂起事件,该列表就会被处理。您可以通过调用帧的
IsBeingDeleted
方法来测试该情况(已关闭但尚未销毁)。此外,UI对象的C++部分也保留了自己对Python对象的引用,尽管在C++对象被销毁时,这将是递减的。因此,这些事情中的一些或全部可能会干扰你的weafref方法。就我个人而言,我只会像上面那样使用
if
语句。短。好极了。简单


另外,我在这里提到的一些细节是针对wxPython Classic的,在凤凰城的处理方式不同。但是,像上面那样使用
if
语句仍然有效。

Perfect
if not windowObject
是我一直在寻找的优雅解决方案!完美的
if not windowObject
是我一直在寻找的优雅解决方案!