PyQt:运行时错误:包装的C/C++对象已被删除

32

如果我运行这段代码:

    #!/usr/local/bin/    python3

import sys 
from PyQt4.QtCore import *
from PyQt4.QtGui import *


class Window(QMainWindow):

    def __init__(self):
        super().__init__()
        self.button1 = QPushButton("1")
        self.button2 = QPushButton("2")
        self.setCentralWidget(self.button1)
        self.button1.clicked.connect(lambda: self.setCentralWidget(self.button2))
        self.button2.clicked.connect(lambda: self.setCentralWidget(self.button1))
        self.show()

if __name__ == '__main__':

    import sys 
    app = QApplication(sys.argv)
    window = Window()
    sys.exit(app.exec_())

...我得到了这个输出:

Traceback (most recent call last):
  File "test.py", line 16, in <lambda>
    self.button2.clicked.connect(lambda: self.setCentralWidget(self.button1))
RuntimeError: wrapped C/C++ object of type QPushButton has been deleted

我不明白为什么对象被删除了。窗口应该保留对它的引用。 我已经彻底调查了这些帖子: Understanding the “underlying C/C++ object has been deleted” error Can a PyQt4 QObject be queried to determine if the underlying C++ instance has been destroyed?

为什么按钮会被删除?


1
我遇到了QWidget的一个子类的类似问题,结果发现问题在于我忘记在我的__init__开头调用QWidget的__init__了。有点诡异。 - spookypeanut
在我们的情况下,调用 a.call_some_parent_method(),其中 a = QObjectA(parent=QObjectB()),引发了一个 RuntimeError: wrapped C/C++ object of type QObjectA has been deleted。然而,实际原因是被包装的类型为 QObjectB 的对象已被删除(而不是错误消息中提到的 QObjectA)。解决方案是同时保留对 QObjectB 的引用:b = QObjectB(); a = QObjectA(parent=b)(使用 Python 2.7、PyQt5)。 - djvg
请参见 https://dev59.com/IG025IYBdhLWcg3wclm-#40053635 - djvg
在我的情况下,一个 QWidget 实例的属性被删除了。原来我只把 QWidget 实例保存到了一个局部变量中,因此垃圾回收器会在变量超出作用域时立即删除其属性。通过保留对 QWidget 实例的永久引用来解决了这个问题。 - SomeDude
5个回答

24
这个问题的答案可以在这里找到:Python PySide (Internal c++ Object Already Deleted) 看起来,使用setCentralWidget将一个小部件分配给QMainWindow,然后再使用setCentralWidget将另一个小部件分配给它,会导致底层的c ++ QWidget被删除,即使我有一个维护对它的引用的对象。
注意:QMainWindow接管小部件指针并在适当的时间删除它。

4
当您运行连续线程并关闭主窗口/对话框但在后台线程正在处理时,PyQT5中也会出现此问题。当您再次打开窗口时,将生成第二个线程并删除预先存在的小部件。在重新运行之前,您需要首先退出线程。您可以通过在主窗口/对话框中的任何小部件上放置检查来退出线程。请注意保留HTML标签。
            **if self.widget.isVisible() == False:
                break**

谢谢你!你救了我的一天!我一直在收到一个 RuntimeError: wrapped C/C++ object Signals has been deleted 的错误。我把所有的信号都放在了一个类里面。我有一个线程在 while(1) 循环中不断地检查外围设备,按照我的设计它应该始终运行。但我实现了一个登录界面,当登出并重新登录时,主 GUI 会被销毁和重新创建,因此这个错误会在登出和重新登录后发生。 - ChumbiChubaGo

3

Brain的回答完美地解释了这个问题。这个链接更详细地解释了这些内容。

我对这个问题的解决方案是将小部件设置为对象的属性(例如,在类方法中仅使用self.label = ...而不是label = ...)。您可能还想对小部件附加的任何布局执行相同的操作。

这样,您就可以创建小部件的副本,因此当进行C++内存清理时,您仍然拥有对小部件的引用。

希望这可以帮助您。


2
在另一种情况下,解决方案是首先将所有子对象添加到一个分离的布局中,然后将该布局作为最后一步添加到父布局中。即:
    l = QGridLayout()
    l.addWidget(QLabel("child1"), 0, 0)
    l.addWidget(QLabel("child2"), 0, 1)
    ...
    parentLayout.addLayout(l)

0

您的答案可以通过添加其他支持信息来改善。请[编辑]以添加更多细节,例如引用或文档,以便他人可以确认您的答案是否正确。您可以在帮助中心中找到有关如何编写良好答案的更多信息。 - Community

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接