2

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?

Community
  • 1
  • 1
Jan Rüegg
  • 9,587
  • 8
  • 63
  • 105
  • Why does the main application close when the dialog is open? Can't you prevent that? – drescherjm Jul 11 '16 at 13:16
  • No, there is a separate thread running that can potentially throw an error. In that case, the application is shut down and all widgets are destroyed. This works fine (all the proper destructors etc. are called), except for a still running getOpenFileName. – Jan Rüegg Jul 11 '16 at 13:40
  • 2
    Have you assigned parent? - may as well post up your code for calling the dialog in-case there is anything obvious – code_fodder Jul 11 '16 at 15:23

2 Answers2

2

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;
}
Tarod
  • 6,732
  • 5
  • 44
  • 50
0

The design of your application is broken. The shut down of the application normally happens when the outernmost event loop in the main thread exists. This won't happen while a file dialog is active - by definition, its event loop is running then. Thus you're doing something you shouldn't be doing, and the file dialog is merely a scapegoat, or a canary in the coalmine indicating brokenness elsewhere.

Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313
  • I think thats not true: To my knowledge, the filedialog will do the same as all dialogs when you call "exec", and start its own internal event loop, see also here: http://stackoverflow.com/a/33606782/369009: "That can be a source of nasty bugs: (Almost) anything can happen before exec() returns, external events (timers, network, IPC, whatever) can call slots, cause other dialogs to appear, etc. J" – Jan Rüegg Jul 12 '16 at 07:20