使用自定义项 class QGraphicsScene::removeItem() 后崩溃
Crash after QGraphicsScene::removeItem() with custom item class
我正在使用自定义项 class 的实例填充 QGraphicsScene
(继承 QGraphicsPathItem
)。在运行时的某个时候,我尝试通过调用从场景中删除一个项目(及其子项目):
delete pItem;
这会自动调用 QGraphicsScene::removeItem()
,但它也会导致 class QGraphicsSceneFindItemBspTreeVisitor
在下一次重绘期间崩溃。
TL;DR: 解决方案是确保 QGraphicsItem::prepareGeometryChange()
在 之前被调用 项目从场景中移除。
问题是在从场景中移除项目的过程中,场景内部索引没有正确更新,导致下次尝试绘制场景时崩溃。
因为在我的例子中,我使用了来自 QGraphicsPathItem
的自定义子类,所以我只是将对 QGraphicsItem::prepareGeometryChange()
的调用放入其析构函数中,因为我没有手动从场景中删除该项目(通过 QGraphicsScene::removeItem()
),但我只是调用 delete pItem;
,它在 return 中触发了项目的析构函数以及稍后的 removeItem()
。
我遇到了这个问题,修复它真的很痛苦。除了崩溃,我的屏幕上还出现了 "guost" 个项目。
我在自定义 updateGeometry() 方法中将 boundingRect 大小更改为 2 倍,该方法更新了项目的边界框和形状缓存。
我正在将边界矩形初始化为 QRectf():
boundingBox = QRectF();
...然后进行一些处理(并借此机会对场景中不需要的对象进行一些清理)。
最后将 boundingRect 的值设置为其新大小:
boundingBox = polygon.boundingRect();
在开始时单独调用 prepareGeometryChange() 并没有解决问题,因为我改变了它的大小两次。
解决方案是删除第一个属性。
我 运行 使用 PySide2 遇到了同样的问题。
禁用 BSP 索引(如前所述 here)对我有用并且很可能是 实际 问题的解决方案。但这是次优的,因为我正在处理的场景可以任意大。我还尝试在删除该项目之前调用 prepareGeometryChange
,虽然这似乎工作了一段时间,但几周后错误再次出现。
对我有用的(到目前为止)是在删除项目本身之前手动删除所有子项目...
为此,我将覆盖 Python:
中的 QGraphicsScene::removeItem
方法
class GraphicsScene(QtWidgets.QGraphicsScene):
def removeItem(self, item: QtWidgets.QGraphicsItem) -> None:
for child_item in item.childItems():
super().removeItem(child_item)
super().removeItem(item)
请注意,这在 C++ 中不会完全相同,因为 QGraphicsScene::removeItem
不是虚方法,因此您可能必须添加自己的方法 removeItemSafely
或其他方法。
免责声明:其他方法也对我有用......直到他们没有。自从引入此解决方法以来,我还没有在 QGraphicsSceneFindItemBspTreeVisitor::visit
中看到崩溃,但这并不意味着这实际上是解决方案。使用风险自负。
今天这个问题似乎持续了很长时间,而且还有未解决的错误。
但它似乎有一个解决方法,我发现它很有用,经过数小时的调试、阅读和调查,我在这里找到了它:
有关图形场景的一些其他提示和技巧:
https://tech-artists.org/t/qt-properly-removing-qgraphicitems/3063/6
我正在使用自定义项 class 的实例填充 QGraphicsScene
(继承 QGraphicsPathItem
)。在运行时的某个时候,我尝试通过调用从场景中删除一个项目(及其子项目):
delete pItem;
这会自动调用 QGraphicsScene::removeItem()
,但它也会导致 class QGraphicsSceneFindItemBspTreeVisitor
在下一次重绘期间崩溃。
TL;DR: 解决方案是确保 QGraphicsItem::prepareGeometryChange()
在 之前被调用 项目从场景中移除。
问题是在从场景中移除项目的过程中,场景内部索引没有正确更新,导致下次尝试绘制场景时崩溃。
因为在我的例子中,我使用了来自 QGraphicsPathItem
的自定义子类,所以我只是将对 QGraphicsItem::prepareGeometryChange()
的调用放入其析构函数中,因为我没有手动从场景中删除该项目(通过 QGraphicsScene::removeItem()
),但我只是调用 delete pItem;
,它在 return 中触发了项目的析构函数以及稍后的 removeItem()
。
我遇到了这个问题,修复它真的很痛苦。除了崩溃,我的屏幕上还出现了 "guost" 个项目。
我在自定义 updateGeometry() 方法中将 boundingRect 大小更改为 2 倍,该方法更新了项目的边界框和形状缓存。
我正在将边界矩形初始化为 QRectf():
boundingBox = QRectF();
...然后进行一些处理(并借此机会对场景中不需要的对象进行一些清理)。
最后将 boundingRect 的值设置为其新大小:
boundingBox = polygon.boundingRect();
在开始时单独调用 prepareGeometryChange() 并没有解决问题,因为我改变了它的大小两次。
解决方案是删除第一个属性。
我 运行 使用 PySide2 遇到了同样的问题。
禁用 BSP 索引(如前所述 here)对我有用并且很可能是 实际 问题的解决方案。但这是次优的,因为我正在处理的场景可以任意大。我还尝试在删除该项目之前调用 prepareGeometryChange
,虽然这似乎工作了一段时间,但几周后错误再次出现。
对我有用的(到目前为止)是在删除项目本身之前手动删除所有子项目... 为此,我将覆盖 Python:
中的QGraphicsScene::removeItem
方法
class GraphicsScene(QtWidgets.QGraphicsScene):
def removeItem(self, item: QtWidgets.QGraphicsItem) -> None:
for child_item in item.childItems():
super().removeItem(child_item)
super().removeItem(item)
请注意,这在 C++ 中不会完全相同,因为 QGraphicsScene::removeItem
不是虚方法,因此您可能必须添加自己的方法 removeItemSafely
或其他方法。
免责声明:其他方法也对我有用......直到他们没有。自从引入此解决方法以来,我还没有在 QGraphicsSceneFindItemBspTreeVisitor::visit
中看到崩溃,但这并不意味着这实际上是解决方案。使用风险自负。
今天这个问题似乎持续了很长时间,而且还有未解决的错误。
但它似乎有一个解决方法,我发现它很有用,经过数小时的调试、阅读和调查,我在这里找到了它:
有关图形场景的一些其他提示和技巧: https://tech-artists.org/t/qt-properly-removing-qgraphicitems/3063/6