4

I am populating a QGraphicsScene with instances of a custom item class (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.

Philip Allgaier
  • 3,505
  • 2
  • 26
  • 53

4 Answers4

6

TL;DR: The solution is to ensure that QGraphicsItem::prepareGeometryChange() gets called before the item's removal from the scene.


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; which in return triggers the item's destructor as well as removeItem() later on.

Philip Allgaier
  • 3,505
  • 2
  • 26
  • 53
2

I ran into the same issue using PySide2.

Disabling BSP indexing (as mentioned here) does work for me and is most likely the actual solution to the problem. 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.

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:

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.

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. Use at your own risk.

Clemens Sielaff
  • 708
  • 10
  • 15
0

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.

I was changing the boundingRect size 2x inside a custom updateGeometry() method that updates the boundingbox and shape caches of the item.

I was initializing the boundig rectangle as 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:

boundingBox = polygon.boundingRect();

Calling prepareGeometryChange() in the beggining, alone, didn't solve the issue since I was changing it's size twice.

The solution was to remove the first attribution.

Adriel Jr
  • 2,451
  • 19
  • 25
0

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

Some other tips and tricks regarding Graphics Scene here: https://tech-artists.org/t/qt-properly-removing-qgraphicitems/3063/6

Ardent Coder
  • 3,777
  • 9
  • 27
  • 53
alexei
  • 9
  • 5