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
QMessageBoxwithsetModal(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
QMessageBoxis behind the parent which has focus (and you can't interact with the parent). Basically, you have to move the parent to reveal theQMessageBoxbefore 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 (
pushButtonis 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_HMainWindow.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::Popupon the Message Box- Changing parent to
MainWindow Qt::WindowStaysOnTopHinton 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
QMessageBoxto be shown as a Mac window drop-down.setModalandsetWindowFlagsseem 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.
-
[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
QMessageBoxwithsetModal(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
QMessageBoxis behind the parent which has focus (and you can't interact with the parent). Basically, you have to move the parent to reveal theQMessageBoxbefore 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 (
pushButtonis 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_HMainWindow.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::Popupon the Message Box- Changing parent to
MainWindow Qt::WindowStaysOnTopHinton the Message Box
...to no avail.
@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::execwhich is for modal-only dialogs, andQt::Popupisn'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.