既然Python中已经有垃圾收集器,那么在PyQt/PySide中需要deleteLater()吗?
import sys
from PyQt5 import QtCore, QtWidgets
class Window(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.checkbox = QtWidgets.QCheckBox('Delete')
self.button = QtWidgets.QPushButton('Open', self)
self.button.clicked.connect(self.openDialog)
layout = QtWidgets.QHBoxLayout(self)
layout.addWidget(self.checkbox)
layout.addWidget(self.button)
def openDialog(self):
widget = QtWidgets.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(QtWidgets.QDialog):
if child is not widget:
child.deleteLater()
label = QtWidgets.QLabel(widget)
button = QtWidgets.QPushButton('Close', widget)
button.clicked.connect(widget.close)
layout = QtWidgets.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__':
app = QtWidgets.QApplication(sys.argv)
window = Window()
window.setGeometry(500, 300, 100, 50)
window.show()
sys.exit(app.exec_())
使用PyQt/PySide时,对象所有权有两个方面:Python部分和Qt部分。通常情况下,仅删除对象的最后一个Python引用是不足以完全清除它的,因为Qt侧可能仍然保留有引用。
一般来说,Qt倾向于不隐式删除对象。因此,如果您的应用程序创建和删除大量QObjects(或打开和关闭大量QWidgets),如果内存使用是一个问题,您可能需要采取措施显式地删除它们。
更新:
只是补充上述关于对象所有权的要点。有时,可能会持有一个Python引用到一个对象,而Qt部分被删除。当这种情况发生时,您将看到如下错误:
RuntimeError: underlying C/C++ object has been deleted
通常,Qt文档会给出一些关于何时可能发生这种情况的提示。例如,QAbstractItemView.setModel 给出了以下警告:
这是在告诉你,你必须要么保留一个Python引用指向该对象,要么将一个合适的父对象传递给该对象的构造函数,因为Qt不会总是自动重设其父对象。除非它是模型的父对象,否则视图不会拥有模型...
deleteLater
的一个应用是清理自己,即安排删除QObject(例如在线程中),以便从对象本身释放资源。
例如,在此处示例中,有人将其与信号thread.finished连接在一起。但它可能仅限于信号传递较重的情况。