gpt4 book ai didi

qt - QGraphicsObject 上的 deleteLater 与 removeItem

转载 作者:行者123 更新时间:2023-12-04 13:28:01 27 4
gpt4 key购买 nike

虽然我通过 PyQt 从 Python 使用 Qt,这个问题同样适用于纯 Qt,只是语法有点不同,问题是一样的:

当我们想要在场景中处理 QGraphicsItem 对象时,我们调用 scene.removeItem(item)。当我们想在场景中处理 QGraphicsObject 对象时,我们调用 scene.removeItem(item) 因为它派生自 QGraphicsItem,但我们也调用 item.deleteLater() 因为它派生自 QObject,这是推荐的处理方式QObjects(以便正确处理进出项目的未决信号)。

问题是,由于 deleteLater() 的功能,对象项目中的槽可能会在项目从场景中移除后被调用。这要求我们测试 self.scene() 在插槽中是否为 None。但这很容易出错,因为很容易忘记这样做,如果调用插槽,忘记这一点会导致异常。

另一种方法是在从场景中移除项目之前不调用 deleteLater() ,但这需要手动断开项目与其他对象的连接。这与测试 self.scene() 在插槽中为 None 有类似的缺点,并且很容易忘记断开插槽。

减轻这种错误来源(如果没有隐藏的陷阱)的更好方法是当项目是 QGraphicsObject 时不调用 scene.removeItem(item),而只调用它的 deleteLater():它似乎,基于一些简单的测试,当项目最终被销毁时,场景会自动从其列表中删除项目。但是,我找不到任何说明这一点的 Qt 文档,我可能很幸运;也许在更现实的情况下,我会遇到内存泄漏或崩溃。

所以我倾向于在 item 是 QGraphicsObject 时调用 deleteLater() 而不调用 removeItem(),你认为这安全吗?

最佳答案

下面是QGraphicsItem析构函数的源代码(取自qt-5.7/qtbase/src/widgets/graphicsview/qgraphicsitem.cpp)。如您所见,它执行了整个清理工作,并调用了场景的内部 removeItemHelper 函数(也由 removeItem 调用)。因此,它似乎设计得很好,可以通过删除来处理删除。

QGraphicsItem::~QGraphicsItem()
{
if (d_ptr->isObject) {
QGraphicsObject *o = static_cast<QGraphicsObject *>(this);
QObjectPrivate *p = QObjectPrivate::get(o);
p->wasDeleted = true;
if (p->declarativeData) {
if (static_cast<QAbstractDeclarativeDataImpl*>(p->declarativeData)->ownedByQml1) {
if (QAbstractDeclarativeData::destroyed_qml1)
QAbstractDeclarativeData::destroyed_qml1(p->declarativeData, o);
} else {
if (QAbstractDeclarativeData::destroyed)
QAbstractDeclarativeData::destroyed(p->declarativeData, o);
}
p->declarativeData = 0;
}
}

d_ptr->inDestructor = 1;
d_ptr->removeExtraItemCache();

#ifndef QT_NO_GESTURES
if (d_ptr->isObject && !d_ptr->gestureContext.isEmpty()) {
QGraphicsObject *o = static_cast<QGraphicsObject *>(this);
if (QGestureManager *manager = QGestureManager::instance()) {
const auto types = d_ptr->gestureContext.keys(); // FIXME: iterate over the map directly?
for (Qt::GestureType type : types)
manager->cleanupCachedGestures(o, type);
}
}
#endif

clearFocus();
setFocusProxy(0);

// Update focus scope item ptr.
QGraphicsItem *p = d_ptr->parent;
while (p) {
if (p->flags() & ItemIsFocusScope) {
if (p->d_ptr->focusScopeItem == this)
p->d_ptr->focusScopeItem = 0;
break;
}
p = p->d_ptr->parent;
}

if (!d_ptr->children.isEmpty()) {
while (!d_ptr->children.isEmpty())
delete d_ptr->children.first();
Q_ASSERT(d_ptr->children.isEmpty());
}

if (d_ptr->scene) {
d_ptr->scene->d_func()->removeItemHelper(this);
} else {
d_ptr->resetFocusProxy();
setParentItem(0);
}

#ifndef QT_NO_GRAPHICSEFFECT
delete d_ptr->graphicsEffect;
#endif //QT_NO_GRAPHICSEFFECT
if (d_ptr->transformData) {
for(int i = 0; i < d_ptr->transformData->graphicsTransforms.size(); ++i) {
QGraphicsTransform *t = d_ptr->transformData->graphicsTransforms.at(i);
static_cast<QGraphicsTransformPrivate *>(t->d_ptr.data())->item = 0;
delete t;
}
}
delete d_ptr->transformData;

if (QGraphicsItemCustomDataStore *dataStore = qt_dataStore())
dataStore->data.remove(this);
}

关于qt - QGraphicsObject 上的 deleteLater 与 removeItem,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41004665/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com