Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

How to handle closeEvent with the QDialog .open() instead of .exec()?



  • Currently within our application, when the window receives a windows closeEvent we display MessageBox, with questions for Save, Discard, Abort so that the user can save the changes.

    In webassembly the widgets .exec() function does not work (see https://bugreports.qt.io/browse/QTBUG-64020).
    With wasm the .exec() function is not available, so it is not possible to block the event queue.
    We need to use the .open() function, so that the closeEvent return before the user has answered the question.
    So we have tried the following:
    • Display a messageBox connected to a lambda function.
    • Call the msg.open()
    • Ignore the event so that the windows does not close
    • In the lambda function that respond to the event QMessageBox::Save
    save the data and close the windows.
    But we have a further problem due to the fact that we use and MDI (multiple document interface). We can have different windows open and the user could cancel the saving of just one window.

    The QDialog documentation advice not to use the exec() function
    “Note: Avoid using this function; instead, use open(). Unlike exec(), open() is asynchronous, and does not spin an additional event loop. This prevents a series of dangerous bugs from happening (e.g. deleting the dialog's parent while the dialog is open via exec()). When using open() you can connect to the finished() signal of QDialog to be notified when the dialog is closed.”

    We would like to know what approach do you suggest to follow in order to use asynch programming within the closeEvent and get rid of the dialog exec() function?


  • Lifetime Qt Champion

    Hi and welcome to devnet,

    Connect the accepted and rejected signals in order to act properly in each cases.

    You have these information in the exec method documentation.



  • We have already used the accepted and rejected signals, but the problem is that at this time the closeEvent message queue is already terminated.

    The issue is quite complex and you find an extensive information (but not related to QT) on:
    https://stackoverflow.com/questions/16656523/awaiting-asynchronous-function-inside-formclosing-event



  • Some of the details of the description are confusing to me, but the general problem does not sound difficult. The desired outcome might be accomplished with:

    class Widget : public QWidget {
        bool delayClose = true;
        QDialog *closeDialog;
    
        Widget(QWidget *parent = nullptr) : QWidget(parent) {
            connect(closeDialog, QDialog::accepted,
                    [&this]() {
                        this->delayClose = false; // closing is now possible
                        this->close();            // close
                    }
            );
        }
    
        void closeEvent(QCloseEvent *event) {
            if (delayClose) {
                event->ignore();     // Don't close now
                closeDialog->show(); // Ask the user to make closing possible 
            }
            else
                QWidget::closeEvent(event);
    }
    

    Replace the setting of delayClose to false with an appropriate heuristic, possibly calculated in the event handler.


  • Lifetime Qt Champion

    Just to be sure I understand the issue: you may have multiple documents to save and each asks to save separately ?


Log in to reply