Is it possible to QProgressDialog::show without bringing the dialog to the front when the application is minimized/hidden?

Viewed 638

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:

enter image description here

I have also tried with the same non-desired behaviour result:

  • Using QDialog::open instead of QWidget::show.
  • Using QDialog::setVisible instead of QWidget::show.
  • Adding progress->setAttribute(Qt::WA_ShowWithoutActivating); before calling progress->show().
  • Adding progress->setWindowFlag(Qt::WindowDoesNotAcceptFocus, true); before calling progress->show();
1 Answers
Related