Modal from a modal (Mac)



  • [This is a cross-post from StackOverflow].

    I have a Qt modal dialog (a complex form) that needs to itself pop up a modal dialog (a QMessageBox with setModal(true)). This modal should be on top of the parent modal form, and prevent interaction.

    This all works swimmingly up to a point - the second modal appears, and prevents interaction with the widgets in the parent. However, the parent form can still receive focus - that is, I can click in it, and the window receives focus (even if I can't interact with the widgets). This becomes a problem if you task away to another application at this point - when you task back the QMessageBox is behind the parent which has focus (and you can't interact with the parent). Basically, you have to move the parent to reveal the QMessageBox before dismissing it.

    Is there a way to have a modal on top of a modal on prevent this problem on Mac OS with window focus and tasking away? (Not tested other OS BTW).

    Example code to reproduce the problem (pushButton is just a standard pushbutton):

    Dialog.cpp

    #include "dialog.h"
    #include "ui_dialog.h"
    
    #include <QMessageBox>
    
    Dialog::Dialog(QWidget *parent) :
        QDialog(parent),
        ui(new Ui::Dialog)
    {
        ui->setupUi(this);
    
        QObject::connect(ui->pushButton, &QPushButton::clicked, this, &Dialog::showMeAModal);
    }
    
    Dialog::~Dialog()
    {
        delete ui;
    }
    void Dialog::showMeAModal()
    {
        QMessageBox box(this);
        box.setText(tr("modal"));
        box.setModal(true);
        box.setWindowFlags(box.windowFlags() | Qt::Popup);
        box.exec();
    }
    

    Dialog.h

    #ifndef DIALOG_H
    #define DIALOG_H
    
    #include <QDialog>
    
    namespace Ui {
    class Dialog;
    }
    
    class Dialog : public QDialog
    {
        Q_OBJECT
    
    public:
        explicit Dialog(QWidget *parent = 0);
        ~Dialog();
    public slots:
        void showMeAModal();
    
    private:
        Ui::Dialog *ui;
    };
    
    #endif // DIALOG_H
    

    MainWindow.cpp

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    

    main.cpp

    #include "mainwindow.h"
    #include <QApplication>
    
    #include "dialog.h"
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        MainWindow w;
        w.show();
    
        Dialog dialog(&w);
        dialog.setModal(true);
        dialog.show();
    
        return a.exec();
    }
    

    I've tried:

    • Qt::Popup on the Message Box
    • Changing parent to MainWindow
    • Qt::WindowStaysOnTopHint on the Message Box

    ...to no avail.



  • I tried your sample code and saw the problem you described only with a specific sequence of events. Your sample code is incomplete but enough was there where I could fill in the rest so I don't think this is critical.

    I am currently running OSX 10.10.5, XCode 7.2.1, Qt 5.6.0.

    The sequence of events that creates this problem is as follows:

    • Click on the button to create the message box.

    • Click focus on the dialog below the message box so this has focus. The mainwindow cannot get focus in this program.

    • Click focus to some other program (i.e. a finder window).

    • Click back to the program (anything other than the messagebox). The messagebox is now behind the dialog (wrong Z order).

    My first thought to solving this would be related to keeping focus on the messagebox when it is visible or maybe tap into the QFocus events and use some combination of raise() or lower() to make sure the messagebox is always on top (these functions change the Z order). I didn't try any of this but it is just an idea.



  • I think I found a solution to this problem. Try this:

    void Dialog::showMeAModal()
    {
        QMessageBox box(this);
        box.setText(tr("modal"));
        box.setModal(true);
        box.setWindowFlags(box.windowFlags() | Qt::Popup);
        box.setWindowModality(Qt::WindowModal);
        box.exec();
    }
    

    It looks a little different that a regular message box (quite cool actually) and your problem no longer exists.



  • Thanks, this is similar to the solution we came up with. The crucial line is

    box.setWindowModality(Qt::WindowModal);
    

    This causes the QMessageBox to be shown as a Mac window drop-down. setModal and setWindowFlags seem to have no additional affect.

    That said, this is a workaround with user interface impact - there does appear to be a bug in Qt that is causing this situation.


  • Qt Champions 2016

    @KevinD said in Modal from a modal (Mac):
    Hi,
    Don't use these two:

    box.setModal(true);
    box.setWindowFlags(box.windowFlags() | Qt::Popup);
    

    You're calling QDialog::exec which is for modal-only dialogs, and Qt::Popup isn't for dialogs, leave the window flags be. If you prepare a MWE (the download-and-build type) I can test on Linux (I have no Mac, sorry). Also you might consider filing a bug report if everything else fails.

    Kind regards.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.