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();
}
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:
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.