c++qtqt5fileopendialogqeventloop

Run QFileDialog::getOpenFileName without separate event loop?


I'm using QFileDialog::getOpenFileName right now. However, as suggested in this article, this crashes when the main application closes while the dialog is open. You can see an example of how to reproduce the crash here:

int main(int argc, char **argv) {
  QApplication application{argc, argv};

  QMainWindow *main_window = new QMainWindow();
  main_window->show();

  QPushButton *button = new QPushButton("Press me");
  main_window->setCentralWidget(button);

  QObject::connect(button, &QPushButton::clicked, [main_window]() {
    QTimer::singleShot(2000, [main_window]() { delete main_window; });

    QFileDialog::getOpenFileName(main_window, "Close me fast or I will crash!");
  });

  application.exec();
  return 0;
}

I can use QFileDialog with the normal constructor instead, as described here. However, then I don't seem to get the native windows file open dialog.

Is there a way to get a non crashing program and use the native Windows file open dialog through Qt?


Solution

  • If you close your main_window instead of deleting it, you won't get any crash.

    By the way, you could check if there is any QFileDialog opened to avoid a wrong app exit.

    In the next example, I'm closing the dialog, but you could implement another solution:

    #include <QTimer>
    #include <QApplication>
    #include <QMainWindow>
    #include <QPushButton>
    #include <QFileDialog>
    #include <QDebug>
    
    int main(int argc, char **argv) {
      QApplication application{argc, argv};
    
      QMainWindow *main_window = new QMainWindow();
      main_window->show();
    
      QPushButton *button = new QPushButton("Press me");
      main_window->setCentralWidget(button);
    
      QObject::connect(button, &QPushButton::clicked, [main_window]() {
        QTimer::singleShot(2000, [main_window]() {
    
            QObjectList list = main_window->children();
    
            while (!list.isEmpty())
            {
                QObject *object= list.takeFirst();
    
                if (qobject_cast<QFileDialog*>(object))
                {
                    qDebug() << object->objectName();
                    QFileDialog* fileDialog = qobject_cast<QFileDialog*>(object);
                    fileDialog->close();
                }
            }
    
            main_window->close();
        });
    
        QFileDialog::getOpenFileName(main_window, "Close me fast or I will crash!");
      });
    
      application.exec();
      return 0;
    }