QFileDialog won't show up when QGraphicsScene::update() is called
-
Hi,
I have stumbled upon an unexpected behavior.
I haveQGraphicsSceneand at some point I would like to save some data to a file. At that pointQFileDialog::getSaveFileName(this)is called, but dialog itself won't show up. Parent window is grayed out, but no dialog is visible. By hitting Esc "invisible" dialog closes and parent window is available again. This behavior seems to be triggered by callingQGraphicsScene::update().Initial state

Button clicked

MainWindow.h
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QGraphicsScene> class MainWindow : public QMainWindow { Q_OBJECT protected: QGraphicsScene *scene; public: MainWindow(QWidget *parent = nullptr); ~MainWindow() {} private slots: void onSceneChanged(const QList<QRectF> ®ion); void onButtonClicked(); }; #endif // MAINWINDOW_HMainWindow.cpp
#include "mainwindow.h" #include <QVBoxLayout> #include <QGraphicsScene> #include <QGraphicsView> #include <QPushButton> #include <QFileDialog> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { QWidget *widget = new QWidget; this->setCentralWidget(widget); QVBoxLayout *layout = new QVBoxLayout; widget->setLayout(layout); QGraphicsView *view = new QGraphicsView(scene = new QGraphicsScene); layout->addWidget(view); scene->setSceneRect(0.0,0.0,100.0,100.0); QObject::connect(scene,&QGraphicsScene::changed,this,&MainWindow::onSceneChanged); QPushButton *button = new QPushButton("Open file dialog"); layout->addWidget(button); QObject::connect(button,&QPushButton::clicked,this,&MainWindow::onButtonClicked); } void MainWindow::onSceneChanged(const QList<QRectF> ®ion) { foreach (const QRectF &oneRegion, region) { // Call to update will prevent QFileDialog to show up scene->update(oneRegion); } } void MainWindow::onButtonClicked() { QString fileName = QFileDialog::getSaveFileName(this); qDebug() << fileName; }When line containing
scene->update(oneRegion);is commented out, dialog shows up as it suppose to.My configuration is Qt 6.8.2, Ubuntu 22.04, x86_64, x11
Thanks for help in advance,
Tomas -
Hi,
Why are you calling update on scene when said scene is emitting the changed signal ?
That's the wrong thing to do.
-
Hi,
I have stumbled upon an unexpected behavior.
I haveQGraphicsSceneand at some point I would like to save some data to a file. At that pointQFileDialog::getSaveFileName(this)is called, but dialog itself won't show up. Parent window is grayed out, but no dialog is visible. By hitting Esc "invisible" dialog closes and parent window is available again. This behavior seems to be triggered by callingQGraphicsScene::update().Initial state

Button clicked

MainWindow.h
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QGraphicsScene> class MainWindow : public QMainWindow { Q_OBJECT protected: QGraphicsScene *scene; public: MainWindow(QWidget *parent = nullptr); ~MainWindow() {} private slots: void onSceneChanged(const QList<QRectF> ®ion); void onButtonClicked(); }; #endif // MAINWINDOW_HMainWindow.cpp
#include "mainwindow.h" #include <QVBoxLayout> #include <QGraphicsScene> #include <QGraphicsView> #include <QPushButton> #include <QFileDialog> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { QWidget *widget = new QWidget; this->setCentralWidget(widget); QVBoxLayout *layout = new QVBoxLayout; widget->setLayout(layout); QGraphicsView *view = new QGraphicsView(scene = new QGraphicsScene); layout->addWidget(view); scene->setSceneRect(0.0,0.0,100.0,100.0); QObject::connect(scene,&QGraphicsScene::changed,this,&MainWindow::onSceneChanged); QPushButton *button = new QPushButton("Open file dialog"); layout->addWidget(button); QObject::connect(button,&QPushButton::clicked,this,&MainWindow::onButtonClicked); } void MainWindow::onSceneChanged(const QList<QRectF> ®ion) { foreach (const QRectF &oneRegion, region) { // Call to update will prevent QFileDialog to show up scene->update(oneRegion); } } void MainWindow::onButtonClicked() { QString fileName = QFileDialog::getSaveFileName(this); qDebug() << fileName; }When line containing
scene->update(oneRegion);is commented out, dialog shows up as it suppose to.My configuration is Qt 6.8.2, Ubuntu 22.04, x86_64, x11
Thanks for help in advance,
Tomas@tomas-soltys
As @SGaist said, connecting the
QGraphicsScene::changedsignal to a function which updates the scene again creates a dead lock / infinite loop because updating the region will also cause the scene to emit the signal again... and again... and again.
So you dialog can't be rendered properly because the event loop is busy with updating the scene forever.
It's the same thing why you should never callrepaint()in some widget'spaintEvent()... same result.
repaint()schedules the repainting of the widget through itspaintEvent()... which then would start everything over again, because therepaint()is there. -
Thanks @SGaist and @Pl45m4 for the hint which eventually lead me to the solution.
The example I provided was just a demonstration that there is an issue when scene update is called too many times and it happens only withQFileDialogand only onX11. In my real code I was not calling update directly but throughQAbstractGraphicsShapeItem::prepareGeometryChange(). Once I reworked my code to call it less frequently dialog shows up.What is so special with
QFileDialogthat it couldn't be rendered but other dialogs likeQMessageBoxcould? -
Thanks @SGaist and @Pl45m4 for the hint which eventually lead me to the solution.
The example I provided was just a demonstration that there is an issue when scene update is called too many times and it happens only withQFileDialogand only onX11. In my real code I was not calling update directly but throughQAbstractGraphicsShapeItem::prepareGeometryChange(). Once I reworked my code to call it less frequently dialog shows up.What is so special with
QFileDialogthat it couldn't be rendered but other dialogs likeQMessageBoxcould?@tomas-soltys
I have tested your pasted code under Ubuntu 24.04, Qt 6.4.2, Xorg desktop. I agree with your findings:QFileDialog::getSaveFileName()(I also tried creating an instance and usingexec()) cannot show the dialog, while aQMessageBoxdoes show up. ThesceneUpdate()inonSceneChanged()causes the issue.I don't know why.
QFileDialogdoes quite a bit more than, say,QMessageBox. From attempting to put in suitableqDebug()s I believeonSceneChanged()is being called continuously in this situation, presumably as a result of thescene->update()class and some interaction with theQFileDialogbeing there or attempting to be there. That might be why you never get to see it.Updating the scene in a slot attached to
QGraphicsScene::changedmay be problematic. It seems to be in this circumstance at least. I think you are saying you have removed or reduced this and things are better. But why do you need to update the scene from its signal saying it has been updated, can't you avoid that? -
QFileDialog is a native dialog so it might react a bit differently with regard to other widgets.