【问题标题】:Crash after QGraphicsScene::removeItem() with custom item class使用自定义项目类在 QGraphicsScene::removeItem() 后崩溃
【发布时间】:2020-05-26 21:25:07
【问题描述】:

我正在使用自定义项目类的实例填充QGraphicsScene(继承QGraphicsPathItem)。在运行时的某个时刻,我尝试通过调用从场景中移除一个项目(及其子项):

delete pItem;

这会自动调用QGraphicsScene::removeItem(),但它也会在下一次重绘期间导致QGraphicsSceneFindItemBspTreeVisitor 类崩溃。

【问题讨论】:

    标签: c++ qt5 qgraphicsitem qgraphicsscene


    【解决方案1】:

    TL;DR:解决方案是确保在项目从场景中移除之前调用QGraphicsItem::prepareGeometryChange()


    问题是在从场景中移除项目的过程中,场景内部索引没有正确更新,导致下次尝试绘制场景时崩溃。

    因为在我的例子中,我使用了来自 QGraphicsPathItem 的自定义子类,所以我只是将调用 QGraphicsItem::prepareGeometryChange() 放入它的析构函数中,因为我没有手动从场景中删除该项目(通过 QGraphicsScene::removeItem()),而是我只是调用delete pItem;,这反过来会触发项目的析构函数以及稍后的removeItem()

    【讨论】:

      【解决方案2】:

      我在使用 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 中看到崩溃,但这并不意味着这实际上就是解决方案。使用风险自负。

      【讨论】:

        【解决方案3】:

        我遇到了这个问题,修复它真的很痛苦。除了崩溃之外,我的屏幕上还出现了“guost”项目。

        我在自定义 updateGeometry() 方法中将 boundingRect 大小更改为 2 倍,该方法更新了项目的边界框和形状缓存。

        我将边界矩形初始化为 QRectf():

        boundingBox = QRectF();
        

        ...然后进行一些处理(并借此机会对场景中不需要的对象进行一些清理)。

        最后将 boundingRect 的值设置为新的大小:

        boundingBox = polygon.boundingRect();
        

        在开始时单独调用 prepareGeometryChange() 并没有解决问题,因为我将它的大小更改了两次。

        解决方案是删除第一个属性。

        【讨论】:

          【解决方案4】:

          这个问题今天似乎持续了很长时间,而且还有一些未解决的错误。

          但它似乎有一个解决方法,我发现它很有用,经过数小时的调试、阅读和调查,我在这里找到了它:

          https://forum.qt.io/topic/71316/qgraphicsscenefinditembsptreevisitor-visit-crashes-due-to-an-obsolete-paintevent-after-qgraphicsscene-removeitem/17

          这里有一些关于图形场景的其他提示和技巧: https://tech-artists.org/t/qt-properly-removing-qgraphicitems/3063/6

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2015-01-08
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多