QGraphicsScene调用removeItem()延迟移除项触发段错误
QGraphicsItem调用removeItem后残留、删除触发段错误问题
问题表现
- 基于C++/Qt的QGraphicsView/QGraphicsScene框架开发简易节点图编辑器
- 调用
scene.removeItem(Item)移除图元后,QGraphicsItem会在场景中残留极短时间才消失 - 移除图元后立即执行delete删除对象会直接触发段错误;注释掉delete代码时,可观察到图元的局部残缺形态在场景中留存约1秒才完全消失
- 已尝试的无效修复操作:
- 移除项前调用
prepareGeometryChange() - 将QGraphicsView更新模式设置为
FullViewportUpdate
- 移除项前调用
问题对应槽函数代码:
void GraphScene::connectionRemoved(QUuid uuid) { //Connections and nodes are stored in QMaps to retrieve them by uuid ConnectionGraphicsItem *connectionItem = connections.value(uuid); if (connectionItem == nullptr) return; removeItem(connectionItem); //Delayed //delete connectionItem; qDebug() << "con removed" << uuid; }
问题根因
- QGraphicsScene的
removeItem操作不会同步触发视图重绘,Qt的界面渲染走事件循环异步调度,默认的脏区标记、重绘触发存在延迟,会导致图元残留 - 直接在移除后delete对象,但是事件循环中可能还存在待执行的、访问该图元指针的渲染/事件遍历逻辑,野指针访问就会触发段错误
- 存储图元的
connectionsQMap、连接绑定的两端节点锚点都还持有该图元的指针,后续场景遍历、节点重绘时会访问到已从场景移除的无效指针,导致局部残缺绘制、崩溃
修复方案
- 移除图元前先清理所有外部持有的该图元指针:从
connections映射表中删除对应键值对,同时通知连接绑定的两个端点锚点解绑该连接,清空锚点侧保存的连接指针 - 替换直接
delete为connectionItem->deleteLater(),将销毁操作投递到事件循环队列,等当前所有待处理的事件、渲染逻辑执行完成后再销毁对象,避免野指针访问 - 移除图元前先调用
update(connectionItem->boundingRect())标记图元所在区域为脏区,强制触发该区域优先重绘,消除图元残留问题
修复后的参考代码:
void GraphScene::connectionRemoved(QUuid uuid) { // 取出指针的同时从映射表中移除对应条目,避免后续持有野指针 ConnectionGraphicsItem *connectionItem = connections.take(uuid); if (connectionItem == nullptr) return; // 解绑两端锚点,清空锚点侧保存的连接指针,方法名根据自身实现调整 connectionItem->startAnchor()->detachConnection(connectionItem); connectionItem->endAnchor()->detachConnection(connectionItem); // 标记图元区域待重绘 update(connectionItem->boundingRect()); // 从场景移除图元 removeItem(connectionItem); // 延迟删除对象,规避事件循环残留访问导致的段错误 connectionItem->deleteLater(); qDebug() << "con removed" << uuid; }
内容的提问来源于stack exchange,提问作者aelsi2
相关产品推荐
相关产品推荐

