简体   繁体   English

QGraphicsScene::removeItem() 使用自定义项类后崩溃

[英]Crash after QGraphicsScene::removeItem() with custom item class

I am populating a QGraphicsScene with instances of a custom item class (inherting QGraphicsPathItem ).我填充一个QGraphicsScene与自定义项目类(inherting的实例QGraphicsPathItem )。 At some point during runtime, I try to remove an item (plus its children) from the scene by calling:在运行时的某个时候,我尝试通过调用从场景中删除一个项目(及其子项):

delete pItem;

This automatically calls QGraphicsScene::removeItem() , however it also leads to a crash in the class QGraphicsSceneFindItemBspTreeVisitor during the next repaint.这会自动调用QGraphicsScene::removeItem() ,但是它也会在下一次重绘期间导致QGraphicsSceneFindItemBspTreeVisitor类崩溃。

TL;DR: The solution is to ensure that QGraphicsItem::prepareGeometryChange() gets called before the item's removal from the scene. TL;DR:解决方案是确保从场景中移除项目之前调用QGraphicsItem::prepareGeometryChange()


The problem is that during the item removal from the scene, the scene internal index was not properly updated, resulting in the crash upon the next attempt of drawing the scene.问题是在从场景中移除项目的过程中,场景内部索引没有正确更新,导致下次尝试绘制场景时崩溃。

Since in my case, I use a custom subclass from QGraphicsPathItem , I simply put the call to QGraphicsItem::prepareGeometryChange() into its destructor since I am not manually removing the item from the scene (via QGraphicsScene::removeItem() ), but instead I simply call delete pItem;因为在我的情况下,我使用QGraphicsPathItem的自定义子类,我只是将调用QGraphicsItem::prepareGeometryChange()放入其析构函数中,因为我没有手动从场景中删除项目(通过QGraphicsScene::removeItem() ),但是相反,我只是调用delete pItem; which in return triggers the item's destructor as well as removeItem() later on.作为回报,稍后会触发项目的析构函数以及removeItem()

I ran into the same issue using PySide2.我使用 PySide2 遇到了同样的问题。

Disabling BSP indexing (as mentioned here ) does work for me and is most likely the actual solution to the problem.禁用索引BSP(如提到这里)不工作对我来说,是最有可能的实际问题的解决。 But is a sub-optimal one, because the scene that I am working with can get arbitrarily large.但是是次优的,因为我正在处理的场景可以变得任意大。 I also tried to call prepareGeometryChange before removing the item, and while that did seem to work for a while, the error re-appeared just a few weeks later.我还尝试在删除项目之前调用prepareGeometryChange ,虽然这似乎工作了一段时间,但几周后错误再次出现。

What worked for me (so far) is manually removing all child items before removing the item itself... To that end, I am overwriting the QGraphicsScene::removeItem method in Python:对我有用的(到目前为止)是在删除项目本身之前手动删除所有子项目......为此,我在 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)

Note that this will not quite work the same in C++ because QGraphicsScene::removeItem is not a virtual method, so you will probably have to add your own method removeItemSafely or whatever.请注意,这在 C++ 中不会完全相同,因为QGraphicsScene::removeItem不是虚拟方法,因此您可能必须添加自己的方法removeItemSafely或其他方法。

Disclaimer: Other methods have worked for me as well ... until they didn't.免责声明:其他方法也对我有用......直到他们没有。 I have not seen a crash in QGraphicsSceneFindItemBspTreeVisitor::visit since introducing this workaround, but that does not mean that this is actually the solution.自从引入此解决方法以来,我还没有在QGraphicsSceneFindItemBspTreeVisitor::visit看到崩溃,但这并不意味着这实际上是解决方案。 Use at your own risk.使用风险自负。

I had this issue and it was a real pain to fix it.我遇到了这个问题,修复它真的很痛苦。 Besides the crash, I was also having "guost" items appearing on the screen.除了崩溃之外,我还在屏幕上出现了“guost”项目。

I was changing the boundingRect size 2x inside a custom updateGeometry() method that updates the boundingbox and shape caches of the item.我在自定义 updateGeometry() 方法中将 boundingRect 大小更改为 2x,该方法更新项目的边界框和形状缓存。

I was initializing the boundig rectangle as QRectf():我将边界矩形初始化为 QRectf():

boundingBox = QRectF();

... then doing some processing (and taking the opportunity to do some clean ups in unneeded objects from the scene). ...然后进行一些处理(并借此机会对场景中不需要的对象进行一些清理)。

And finally setting the value of the boundingRect to its new size:最后将 boundingRect 的值设置为其新大小:

boundingBox = polygon.boundingRect();

Calling prepareGeometryChange() in the beggining, alone, didn't solve the issue since I was changing it's size twice.在开始时单独调用 prepareGeometryChange() 并没有解决问题,因为我改变了它的大小两次。

The solution was to remove the first attribution.解决方案是删除第一个归因。

It seems the issue lasting for long time today and there are open bugs also.今天似乎这个问题持续了很长时间,并且也有开放的错误。

But it seems to have a workaround, which I could find it useful and after hours of debugging and reading and investigations I have found it here:但它似乎有一个解决方法,我发现它很有用,经过数小时的调试、阅读和调查,我在这里找到了它:

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

Some other tips and tricks regarding Graphics Scene here: https://tech-artists.org/t/qt-properly-removing-qgraphicitems/3063/6关于图形场景的其他一些技巧和窍门: https : //tech-artists.org/t/qt-properly-removing-qgraphicitems/3063/6

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM