clear widget in a QGraphicsScene : crash

2019-07-11 00:43发布

I have a QGraphicsScene with a QPushButton inside, and clearing this scene will crash my application. Is there a correct way to clear a scene with a QWidget ?

The following code crashes when clicking on the button:

#include <QApplication>
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QGraphicsProxyWidget>
#include <QPushButton>

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);

    QGraphicsScene *scene = new QGraphicsScene();

    QGraphicsView *view = new QGraphicsView();
    view->setScene(scene);
    view->show();

    QPushButton *button = new QPushButton("button");
    QObject::connect(button, SIGNAL(clicked()), scene, SLOT(clear()));

    QGraphicsProxyWidget *proxy = scene->addWidget(button);

    return app.exec();
}

标签: c++ qt4
1条回答
爱情/是我丢掉的垃圾
2楼-- · 2019-07-11 01:27

The reason your program crashes is that the QGraphicsScene::clear() method deletes the QButton (and its associated data structures) in the middle of a method call that uses those very data structures. Then, immediately after clear() returns, the calling method tries to access the now-deleted data (because it wasn't expecting to be deleted in the middle of its routine), and bang -- a crash. Your problem is an example of a re-entrancy problem.

The easiest way to avoid tripping over your shoelaces like that is to make your signal/slot connection be a QueuedConnection rather than an AutoConnection:

 QObject::connect(button, SIGNAL(clicked()), scene, SLOT(clear()), Qt::QueuedConnection);

That way the clear() method call won't be executed until after the button's mouse-press-handling routine has returned, and therefore clear() will be called from a context where it is safe to delete the button.

查看更多
登录 后发表回答