Adding a QWidget to a QGraphicsScene, clearing it, then adding the QWidget again



  • Hello,

    here's a code sample:

    auto myQGraphicsScene = new QGraphicsScene();
    // ...
    auto myQWidget = new QWidget();
    // ...
    myQGraphicsScene->addWidget(myQWidget);
    // ...
    myQGraphicsScene->clear();
    // ...
    myQGraphicsScene->addWidget(myQWidget);
    

    I get a segmentation fault at the last line. What am I missing?

    Thanks in advance for your input!


  • Qt Champions 2016

    Hi,
    The graphics scene takes ownership of the widget through the QGraphicsProxyWidget object returned by QGraphicsScene::addWidget. When you call QGraphicsScene::clear the scene deletes all items (including your widget), so myQWidget becomes a dangling pointer. After that you pass a pointer that references an invalid memory location to the QGraphicsScene::addWidget and ... voila! you get a segfault.



  • @kshegunov

    Thank you for the reply. To solve this tidily, could you please confirm that the following is efficient:

    For every QWidget added to the QGraphicsScene this way:

    1. Remove it from the QGraphicsScene thanks to QGraphicsScene::removeItem.
    2. delete its QGraphicsProxyWidget afterward.

    Is anything else required? Do I need to set the QWidget's parent to nullptr or anything else before adding it to the QGraphicsScene again?


  • Qt Champions 2016

    @Pippin said in Adding a QWidget to a QGraphicsScene, clearing it, then adding the QWidget again:

    Is anything else required?

    No, this should be just enough.

    Do I need to set the QWidget's parent to nullptr or anything else before adding it to the QGraphicsScene again?

    Nope, Qt should have done that for you when you removed the item from the scene.



  • @kshegunov said in Adding a QWidget to a QGraphicsScene, clearing it, then adding the QWidget again:

    Nope, Qt should have done that for you when you removed the item from the scene.

    Well technically I didn't remove the QWidget, but its QGraphicsProxyWidget. At this point, both QWidget's and QGraphicsProxyWidget's parent is nullptr then, correct?


  • Qt Champions 2016

    @Pippin said in Adding a QWidget to a QGraphicsScene, clearing it, then adding the QWidget again:

    Well technically I didn't remove the QWidget, but its QGraphicsProxyWidget. At this point, both QWidget's and QGraphicsProxyWidget's parent is nullptr then, correct?

    I can't say for sure without actually testing it out, but you should get a QWidget that has a parent QGraphicsProxyWidget. Whereas the QGraphicsProxyWidget should have no parent.



  • @kshegunov So this is the function I've been using:

    void freeWidget(QWidget* foo)
    {
    	const auto proxy = foo->graphicsProxyWidget();
    	myClass::myStaticQGraphicsScene->removeItem(proxy);
    	foo->setParent(nullptr);
    	delete proxy;
    }
    

    But even after that, when I add the QWidget again to myClass::myStaticQGraphicsScene, I get a segmentation fault. Sometimes the following message is printed shorty before:

    QGraphicsProxyWidget::setWidget: cannot embed widget 0x247f680; already embedded
    

    Any insight?



  • I apologize but I'd like to bump this. Is there a way to set a Widget's QGraphicsProxyWidget to nullptr as well? Clearly what I'm doing isn't enough.

    Solved: Indeed I had to set the Widget's QGraphicsProxyWidget to nullptr but the tricky part is, you can only do that from the QGraphicsProxyWidget, not from the QWidget. Here's the fixed freeWidget function:

    void freeWidget(QWidget* foo)
    {
    	const auto proxy = foo->graphicsProxyWidget();
    	myClass::myStaticQGraphicsScene->removeItem(proxy);
    	proxy->setWidget(nullptr);
    	foo->setParent(nullptr);
    	delete proxy;
    }
    

    Thanks again @kshegunov for your help yesterday.

    (Edit: it seems that foo->setParent(nullptr); is useless.)


  • Qt Champions 2016

    Thanks for posting the solution.

    @Pippin said in Adding a QWidget to a QGraphicsScene, clearing it, then adding the QWidget again:

    it seems that foo->setParent(nullptr); is useles

    proxy->setWidget(nullptr);
    

    will set the widget's parent to null for you, yes.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.