0
votes

I have an application which has several background tasks running in non-GUI threads which may time to time require some user interaction so they send signal to the main thread and the corresponding slot creates a dialog and shows it to the user. Meanwhile the task thread is waiting in a blocking event loop. Once the user answers the dialog and closes it, the task event loop is signaled to quit and the task resumes.

There is however a problem. In the GUI thread I can still use the application which time to time shows some modal dialogs. When there is a modal dialog already shown and then the background tasks requests another dialog to be opened, this task-related dialog is displayed in front of the modal dialog. But this new dialog is not modal and the modal dialog is hidden behind it. The non-modal one therefore is not responsive, the application feels like it got stuck.

My idea was to display the new dialog always behind the modal dialog, which I believe I can get with QApplication::activeModalWidget(). But I do not know how to do this. How can I show a dialog behind another dialog but still in front of the main window (which is a parent of both dialogs)? I tried to call QApplication::activeModalWidget()->activateWindow() after I show the non-modal one but his causes blinking of windows and moreover I can still click into the new non-modal dialog hiding the modal one. So this is not a perfect solution.

Or do you see any other solution?

Maybe I could implement a queue of dialogs, and once there is any modal dialog visible, then the new background task-related dialog would not be shown, only enqueued and shown once the modal dialog is closed. However this feels more fragile solution to me.

Any ideas?

UPDATE: I redefined the question by adding "or after it is closed" becasue this works for me too.

2

2 Answers

0
votes

I found a solution which seems to work well and which shows the non-modal dialog only after the modal dialog is closed.

QWidget *nonModalDialog = ... // creates the non-modal dialog
nonModalDialog->setAttribute(Qt::WA_DeleteOnClose);
QWidget *modalDialog = qApp->activeModalWidget();
if (modalDialog == nullptr)
{
    // no modal dialog, we can show the non-modal one now
    dialog->show();
}
else
{
    // we must wait until the modal one is closed
    QObject::connect(modalDialog, &QWidget::destroyed, nonModalDialog, &QWidget::show);
}

This seems simple and robust.

0
votes

I think you are looking for QWidget::raise(). You should be able to use QApplication::activeModalWidget()->raise() after calling dialog->show() on your non-modal dialog.

If you're getting into situations where you have multiple modal and non-modal dialogs, all launched in different order, this might not be enough to solve the problem. You might raise one modal dialog only to have others behind other non-modal dialogs and end up stuck again. You should consider keeping a reference to the collection of modal dialogs that are currently active so that you can make sure they are always on top of the non-modal dialogs.