Mr.Jupiter
Mr.Jupiter

Reputation: 47

Why cannot addItem into QGraphicsScene from a QVector<QGraphicsItem>?

I want to undo or redo actions in a QGraphicsScene that is linked to a QGraphicsView: For that, I use QGraphicsEllipse (to draw points while moving and clicking on the QGraphicsView) in my mouseMoveEvent method, I push every QGraphicsEllipse in a QVector<QGraphicsItem>, and when the QAction "undo" is triggered the program must delete the last ellipses (determined number of ellipses) drawn in my QGraphicsView thanks to my QGraphicsScene.

When I clear my QGraphicsScene and try to add all QGraphicsItems that were pushed in my QVector<QGraphicsItem>, I got an error: my app goes down!

    if(index < historyIndex.size()){
        for (int i = 0; i < scHistory.size() - historyIndex[index]; i++){
            scene->addItem((QGraphicsItem*)scHistory[i]);
         }
        index++;
    }

    QVector<QGraphicsItem *> scHistory;

Upvotes: 2

Views: 527

Answers (1)

cbuchart
cbuchart

Reputation: 11575

QGraphicsScene::addItem takes the ownership of the element added, check the doc. It means that it is now in charge of destructing the element, which happens when you clear the scene with QGraphicsScene::clear. From that point on, your vector is full of dangling pointers.

One quick fix is to replace the call to QGraphicsScene::clear with a manual removal of items through QGraphicsScene::removeItem, which doesn't destroy the item (it returns the ownership to the caller). Then, destroy only those elements that are actually out of the scene, and add back the rest. Another option, more efficient, is to remove only the elements you need, keeping the rest, so you also increase performance by avoiding add back a large number of items from the history.

Without a full knowledge of your code, the second options may be something like:

if(_indexHistoryRoam < _indexHistory.size()){
    // Remove only items beyond history
    const int range = _sceneHistory.size() - _indexHistory[_indexHistoryRoam];
    for (int i = range; i < _sceneHistory.size(); i++){
        scene->removeItem((QGraphicsItem*)_sceneHistory[i]);
        delete _sceneHistory[i]; // item must be destroyed to avoid a leak
     }
    _indexHistoryRoam++;
} else { // force removal of all elements
    scene->clear();
}
scene->update();

Upvotes: 2

Related Questions