PyQt/PySide 中是否需要 deleteLater()? [英] Is deleteLater() necessary in PyQt/PySide?

查看:132
本文介绍了PyQt/PySide 中是否需要 deleteLater()?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

既然Python中已经有了垃圾收集器,那么PyQt/PySide中是否需要deleteLater()?

Since there is already a Garbage Collector in Python, is deleteLater() necessary in PyQt/PySide?

推荐答案

这取决于你所说的必要"是什么意思.

It depends what you mean by "necessary".

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

An application could potentially consume a lot of memory if (for example) care is not taken when closing widgets. The QObject-based classes are designed to be (optionally) linked together in a hierarchy. When a top-level object is deleted, Qt will automatically delete all its child objects as well. However, when closing widgets (which are sub-classes of QObject), automatic deletion will only happen if the Qt.WA_DeleteOnClose attribute is set (which, by default, it usually isn't).

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

To illustrate, try repeatedly opening and closing the dialog in this demo script, and watch how the global list of objects grows:

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 端仍然可能保留一个引用.

With PyQt/PySide, there are two aspects to object ownership: the Python part, and the Qt part. Often, removing the last Python reference to an object won't be enough to fully clean up, because there could still be a reference held on the Qt side.

一般来说,Qt 倾向于隐式删除对象.因此,如果您的应用程序创建和删除了大量 QObject(或打开和关闭了大量 QWidget),如果内存使用问题,您可能需要采取措施明确删除它们.

In general, Qt tends not to implicity delete objects. So if your application creates and removes lots of QObjects (or opens and closes lots of QWidgets), you may need to take steps to delete them explicitly if memory usage is a concern.

更新:

只是为了补充上面关于对象所有权的要点.有时,可能会保留对对象的 Python 引用,而 Qt 部分会被删除.发生这种情况时,您会看到如下错误:

Just to add to the points above on object ownership. Sometimes, it is possible to hold a Python reference to an object, whilst the Qt part gets deleted. When this happens, you will see an error like this:

运行时错误:底层 C/C++ 对象已被删除

RuntimeError: underlying C/C++ object has been deleted

通常,Qt 文档会给出一些有关何时可能发生的提示.例如,QAbstractItemView.setModel 给出了这个警告:

Usually, the Qt documentation will give some hints about when this might happen. For instance, QAbstractItemView.setModel gives this warning:

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

The view does not take ownership of the model unless it is the model's parent object...

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

This is telling you that you must either keep a Python reference to the object, or pass a suitable parent object to the object's constructor, because Qt will not always automatically reparent it.

这篇关于PyQt/PySide 中是否需要 deleteLater()?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆