I have an application that when you press a button it launches two processes one after the other. Both take some time. So it is topical for the user to minimize the window of my app or change to another window to do something while he/she waits. The problem is that when the first process finishes and the second one starts,QProgressDialog::show is called and the widget is shown on top of all other windows in the os, changing the focus of whatever the user is doing in another software. I do not want that to happen. I want the progress dialog to be shown only to the parent widget/application, but if the application is not shown (i.e. it is behind some other window in the os) it should not be brought to the front.
Here is an example that reproduces my problem:
#include <QApplication>
#include <QGridLayout>
#include <QLabel>
#include <QProgressDialog>
#include <QPushButton>
#include <QTimer>
#define WAIT_TIME_MS 3000
QProgressDialog* createProgress(const QString& title, QWidget* parent = nullptr)
{
QProgressDialog* progress = new QProgressDialog(title, "", 0, 0, parent);
progress->setWindowTitle("Progress dialog");
progress->setWindowFlag(Qt::CustomizeWindowHint, true);
progress->setWindowFlag(Qt::WindowCloseButtonHint, false);
progress->setWindowFlag(Qt::WindowContextHelpButtonHint, false);
progress->setWindowModality(Qt::WindowModal);
progress->setCancelButton(nullptr);
progress->show();
return progress;
}
int main(int argc, char** argv)
{
// Create application
QApplication app(argc, argv);
// Create widget
QWidget* w = new QWidget;
w->setLayout(new QGridLayout);
w->setMinimumSize(QSize(800, 600));
// Add button
QPushButton* pb = new QPushButton("Push to compute");
w->layout()->addWidget(pb);
// Add label
w->layout()->addWidget(new QLabel("Compile version: " + QString::fromUtf8(QT_VERSION_STR)));
w->layout()->addWidget(new QLabel("Runtime version: " + QString::fromUtf8(qVersion())));
// Connect push button click
QObject::connect(pb, &QPushButton::clicked, pb, [w]() {
// Create first progress dialog
QProgressDialog* progress_1 = createProgress("First progress dialog", w);
// After WAIT_TIME_MS milliseconds show the progress dialog
QTimer::singleShot(WAIT_TIME_MS, [w, progress_1]() {
// Close previous progress
progress_1->hide();
progress_1->deleteLater();
// Create progress dialog
QProgressDialog* progress_2 = createProgress("Second progress dialog", w);
// Hide and destory progress dialog after WAIT_TIME_MS more milliseconds
QTimer::singleShot(WAIT_TIME_MS, [progress_2]() {
progress_2->hide();
progress_2->deleteLater();
});
});
});
w->show();
return app.exec();
}
If you compile the example, run it and click the button, and after that change to some other program, when the first process finishes my app will appear again on top.
One option would be to merge the two processes, but it is not a solution for the real application as the two processes happen in different widgets as a result of a trigger of the first process. Moreover, the second process can be done by itself as well...
Any idea on how to "show" the progress dialog to the application but not bring the application to the front automatically as a consequence of that QProgressDialog::show?
This happens to me in Ubuntu 18.04 with Qt 5.9.5, Qt 5.13.2, Qt 5.14.2 and Qt 5.15.0. I have also tried with Windows and Qt 5.14.2 obtaining the desired behavior with the code as is above. Here you can see a gift of the behavior that is not desired, first with Qt 5.13.2 and then with Qt 5.9.5:
I have also tried with the same non-desired behaviour result:
- Using
QDialog::openinstead ofQWidget::show. - Using
QDialog::setVisibleinstead ofQWidget::show. - Adding
progress->setAttribute(Qt::WA_ShowWithoutActivating);before callingprogress->show(). - Adding
progress->setWindowFlag(Qt::WindowDoesNotAcceptFocus, true);before callingprogress->show();
