QWidget未随父窗口删除

4 投票
1 回答
2150 浏览
提问于 2025-04-17 05:32

使用下面的代码,我的预览小部件的 __del__ 方法从来没有被调用。如果我把 "del window" 这一行取消注释,它就会被调用。为什么会这样呢?

#!/usr/bin/env python

from PyQt4 import QtGui

class Preview(QtGui.QWidget):
  def __init__(self, parent):
    QtGui.QWidget.__init__(self, parent)

  def __del__(self):
    print("Deleting Preview")

class PreviewWindow(QtGui.QMainWindow):
  def __init__(self):
    QtGui.QMainWindow.__init__(self)

    self.widget = Preview(self)
    self.setCentralWidget(self.widget)

  def __del__(self):
    print("Deleting PreviewWindow")

if __name__ == "__main__":
  app = QtGui.QApplication(["Dimension Preview"])
  window = PreviewWindow()
  window.show()
  app.exec()
  # del window

1 个回答

2

如果一个 QObject 的子类有父对象,那么当父对象被删除时,Qt会自动删除这个子对象。相反,如果这个 QObject 的子类没有父对象,它最终会被Python删除。

希望这个例子能让事情变得更清楚:

from PyQt4 import QtGui

class Widget(QtGui.QWidget):
    def __init__(self, parent):
        QtGui.QWidget.__init__(self, parent)
        self.destroyed.connect(self.handleDestroyed)

    def __del__(self):
        print ('__del__:', self)

    def handleDestroyed(self, source):
        print ('destroyed:', source)

class Foo(Widget):
    def __init__(self, parent):
        Widget.__init__(self, parent)

class Bar(Widget):
    def __init__(self, parent):
        Widget.__init__(self, parent)

class Window(Widget):
    def __init__(self, parent=None):
        Widget.__init__(self, parent)
        self.foo = Foo(self)
        self.bar = Bar(None)

if __name__ == "__main__":

    app = QtGui.QApplication([__file__, '-widgetcount'])
    window = Window()
    window.show()
    app.exec_()

输出结果是:

__del__: <__main__.Window object at 0x88f514c>
destroyed: <__main__.Foo object at 0x88f5194>
__del__: <__main__.Bar object at 0x88f51dc>
Widgets left: 0    Max widgets: 4 

编辑

经过再考虑,似乎某些版本的PyQt4可能存在一个bug(或者至少行为有所不同)。

作为一个可能的解决办法,创建两个Python名字来指向主控件,然后明确地删除这两个名字,可能有助于确保对象的C++和Python两边都被销毁。

如果在上面的脚本中添加以下这一行:

tmp = window; del tmp, window

那么输出结果变成:

__del__: <__main__.Window object at 0x8d3a14c>
__del__: <__main__.Foo object at 0x8d3a194>
__del__: <__main__.Bar object at 0x8d3a1dc>
Widgets left: 0    Max widgets: 4

撰写回答