PyQt / PySide中是否需要deleteLater()?

时间:2013-11-23 15:16:17

标签: python qt pyqt pyside

由于Python中已经有垃圾收集器,PyQt / PySide中是否需要deleteLater()?

2 个答案:

答案 0 :(得分:16)

这取决于你所说的“必要”。

如果(例如)在关闭小部件时不小心,应用程序可能可能消耗大量内存。基于QObject的类被设计为(可选地)在层次结构中链接在一起。删除顶级对象时,Qt也会自动删除其所有子对象。但是,当关闭窗口小部件(它们是QObject的子类)时,只有在设置了Qt.WA_DeleteOnClose属性时才会自动删除(默认情况下,它通常不是)。

为了说明,尝试在此演示脚本中重复打开和关闭对话框,并观察全局对象列表的增长情况:

from PyQt4 import QtCore, QtGui

class Window(QtGui.QWidget):
    def __init__(self):
        QtGui.QWidget.__init__(self)
        self.checkbox = QtGui.QCheckBox('Delete')
        self.button = QtGui.QPushButton('Open', self)
        self.button.clicked.connect(self.openDialog)
        layout = QtGui.QHBoxLayout(self)
        layout.addWidget(self.checkbox)
        layout.addWidget(self.button)

    def openDialog(self):
        widget = QtGui.QDialog(self)
        if (self.checkbox.isChecked() and
            not widget.testAttribute(QtCore.Qt.WA_DeleteOnClose)):
            widget.setAttribute(QtCore.Qt.WA_DeleteOnClose)
            for child in self.findChildren(QtGui.QDialog):
                if child is not widget:
                    child.deleteLater()
        label = QtGui.QLabel(widget)
        button = QtGui.QPushButton('Close', widget)
        button.clicked.connect(widget.close)
        layout = QtGui.QVBoxLayout(widget)
        layout.addWidget(label)
        layout.addWidget(button)
        objects = self.findChildren(QtCore.QObject)
        label.setText('Objects = %d' % len(objects))
        print(objects)
        widget.show()

if __name__ == '__main__':

    import sys
    app = QtGui.QApplication(sys.argv)
    window = Window()
    window.setGeometry(500, 300, 100, 50)
    window.show()
    sys.exit(app.exec_())

使用PyQt / PySide,对象所有权有两个方面:Python部分和Qt部分。通常,删除对象的最后一个Python引用将不足以完全清理,因为在Qt端仍然可以存在引用。

一般来说,Qt倾向于而不是来隐瞒删除对象。因此,如果您的应用程序创建并删除了大量QObject(或打开并关闭了大量QWidgets),那么可能需要采取措施,如果需要考虑内存使用情况,请明确删除它们。

<强>更新

只是添加上面关于对象所有权的要点。有时,可以保存对象的Python引用,同时删除Qt部分。发生这种情况时,您会看到如下错误:

  

RuntimeError:基础C / C ++对象已被删除

通常,Qt文档会给出一些关于何时会发生这种情况的提示。例如,QAbstractItemView.setModel会发出此警告:

  

视图不会取得模型的所有权,除非它是模型的父对象......

这告诉您必须保留对该对象的Python引用,或者将合适的父对象传递给该对象的构造函数,因为Qt不会总是自动重新显示它。

答案 1 :(得分:1)

deleteLater的一个应用程序可以清理自己,即安排删除QObject(例如在线程中)以从对象本身内释放资源。

这里有example有人在信号thread.finished中使用它。它可能仅限于信号较重的病例。