Hi all,

I'm developing a desktop (Windows 10) application that needs to perform some very slow initilization (including file search in all local units). For this reason, I want to issue a QProgressDialog just after the main window is visible to inform the user about the progress of the initialization.

I've been loooking in forums for several days, and this problem seemed to be solved in up to four ways, but I can't it get it with any of the four methods.

So far, I'm getting my best results by overloading showEvent, and launching my initialization function (just once by using a control variable) inside showEvent after the main window is visible (see option 1 in code below). However, the result is unsatisfactory because, although I can see both the main window and the QProgressDialog, this does not show any motion in the progress bar until a (fake) QMessageBox is issued after the initialization process (please see the pictures below). If the message were not issued, the QProgressDialog would never appear.

TestInit1-1(show+processEvents).png

TestInit1-2.jpg

By the way, is it possible to change the aspect of the bar in the QProgressDialog to make its text invisible, and so the bar will expand to the width of the dialog (just like in Qt Design editor, where setting "textVisible" = false gets this effect)? Or this can be made only by customizing the bar with "setBar"?

With the other three options proposed in forums I get absolutely worse results, including a Debug error. So, I must be doing something wrong, but I can't guess what. Can anyone teel me what I'm doing wrong, please?

I attach all the code (MainWindow.h and MainWindow.cpp; I don't think MainWindow.ui is necessary) in case someone may want to test. Note that all four options are implemented (although the three "worse" ones are commented) and can be tested.

MainWindow.h

Qt Code:
  1. #include <QDir>
  2. #include <QFile>
  3. #include <QIODevice>
  4. #include <QTextStream>
  5. #include <QProcess>
  6. #include <QStorageInfo>
  7. #include <QTimer>
  8. #include <windows.h>
  9.  
  10. #include <QWidget>
  11. #include <QMessageBox>
  12.  
  13. namespace Ui
  14. {
  15. class MainWindow;
  16. }
  17.  
  18. class MainWindow : public QMainWindow
  19. {
  20. Q_OBJECT
  21.  
  22. protected:
  23. void showEvent(QShowEvent *ev);
  24.  
  25. // Options 1, 2 and 3: Comment signals declaration.
  26. // Option 4: Uncomment signal declaration.
  27. //signals:
  28. // void window_loaded();
  29.  
  30. public:
  31. explicit MainWindow(QWidget *parent = nullptr);
  32. ~MainWindow();
  33.  
  34. private slots:
  35. void on_actionInitializeTestInit();
  36. void on_actionExit_triggered();
  37.  
  38. private:
  39. QLabel* Label1;
  40. QLabel* Label2;
  41. bool TestInit_started;
  42.  
  43. void CreateStatusBar();
  44. void SearchFiles(const QString &start_path, QStringList &File_list);
  45.  
  46. Ui::MainWindow *ui;
  47.  
  48. };
  49.  
  50. #endif // MAINWINDOW_H
To copy to clipboard, switch view to plain text mode 

MainWindow.cpp

Qt Code:
  1. #include <QtGlobal>
  2. #include "MainWindow.h"
  3. #include "ui_MainWindow.h"
  4.  
  5. MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
  6. {
  7. ui->setupUi(this);
  8.  
  9. TestInit_started = false;
  10.  
  11. // Options 1, 2 and 3: Comment "connect"
  12. // Option 4: Uncomment "connect" to connect my initialization function to
  13. // a signal which will be issued after showing MainWindow
  14. // connect(this, SIGNAL(MainWindow::window_loaded()), this, SLOT(on_actionInitializeTestInit()), Qt::ConnectionType(Qt::QueuedConnection | Qt::UniqueConnection));
  15.  
  16. QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
  17.  
  18. // Initialize some internal elements
  19.  
  20. QApplication::restoreOverrideCursor();
  21. }
  22.  
  23. MainWindow::~MainWindow()
  24. {
  25. delete ui;
  26. }
  27.  
  28. void MainWindow::showEvent(QShowEvent *ev)
  29. {
  30. QMainWindow::showEvent(ev);
  31. if (!TestInit_started)
  32. // Option 1: Comment "QMetaObject", "on_action..." and "emit", and
  33. // uncomment "QTimer"
  34. QTimer::singleShot(0, this, SLOT(on_actionInitializeTestInit()));
  35. // Option 2: Comment "QTimer", "on_action..." and "emit", and
  36. // uncomment "QMetaObject"
  37. // RESULT: Debugging error: Dead lock detected in BlockingQueuedConnection: Receiver is MainWindow(0x78fd00)
  38. // QMetaObject::invokeMethod(this, "on_actionInitializeTestInit", Qt::ConnectionType(Qt::QueuedConnection | Qt::UniqueConnection));
  39. // Option 3: Comment "QTimer", "QMetaObject" and "emit", and uncomment
  40. // "on_action..."
  41. // on_actionInitializeTestInit();
  42. // Option 4: Comment "QTimer", "QMetaObject" and "on_action...", and
  43. // uncomment "emit" to issue signal "window_loaded"
  44. // emit MainWindow::window_loaded();
  45. }
  46.  
  47. void MainWindow::on_actionInitializeTestInit()
  48. {
  49. if (TestInit_started) // Yes, this check is written twice. Just in case...
  50. return;
  51.  
  52. TestInit_started = true;
  53.  
  54. QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
  55.  
  56. // Launch progress dialog. It's configured as a busy indicator because the
  57. // task to perform next is very slow. By the way, is it possible to change
  58. // the aspect of the bar to make its text invisible (just like in the
  59. // Design editor, where setting "textVisible" = false gets), and so the bar
  60. // will expand to the width of the dialog? Or that can be made only by
  61. // customizing the bar with "setBar"?
  62. // Regarding the progress dialog refresh, I've tried with "show", "repaint"
  63. // "update" and "processEvents". If I don't "show", the progress dialog
  64. // doesn't appear; if I don't "processEvents", the progres bar in the
  65. // progress dialog doesn't appear. So, this is my best combination so far.
  66. QProgressDialog progress(this);
  67. // progress.setWindowModality(Qt::WindowModal);
  68. progress.setMinimumWidth(350);
  69. progress.setWindowTitle("Initializing TestInit");
  70. progress.setLabelText("Searching files. This operation may last some minutes. Please wait...");
  71. progress.setCancelButton(nullptr);
  72. progress.setRange(0, 0);
  73. progress.setAutoClose(true);
  74. // progress.setValue(1);
  75. progress.show();
  76. // progress.repaint();
  77. // progress.update();
  78. qApp->processEvents();
  79.  
  80.  
  81.  
  82. // First initialization step: Search in the whole system important files
  83. // for the application. This is a very slow operation, and that's why
  84. // the progress dialog is used as a busy indicator.
  85. // You can customize the file name to search in SearchFiles function below.
  86. QStringList File_list;
  87. foreach (const QStorageInfo &storage, QStorageInfo::mountedVolumes())
  88. {
  89. if (storage.isValid() && storage.isReady() && !storage.isReadOnly() &&
  90. ((storage.device().startsWith("\\\\?")) || (storage.device().startsWith("/dev/sda0"))))
  91. {
  92. QString rootpath(QDir::toNativeSeparators(storage.rootPath()));
  93. SearchFiles(rootpath, File_list);
  94. }
  95. }
  96.  
  97.  
  98. // This block is included just for entertainment. After the search, it
  99. // issues an info message showing the files found.
  100. // In the real application this message will not appear. The problem is
  101. // that the progress dialog does not appear until this message is issued.
  102. // Why?
  103. QApplication::restoreOverrideCursor();
  104. QString allfiles;
  105. for (int i = 0; (i < File_list.size()); i++)
  106. {
  107. if (allfiles.size() > 0)
  108. allfiles += '\n';
  109. allfiles += File_list.at(i);
  110. }
  111. QMessageBox::information(this, "Files found", allfiles, QMessageBox::Ok, QMessageBox::Ok);
  112. QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
  113.  
  114.  
  115. // Other initializations are performed here. These are faster than the
  116. // previous one, and the progress dialog now behaves as usual.
  117. progress.setLabelText("Doing something else (1).");
  118. progress.setRange(0, 1);
  119. progress.setAutoClose(true);
  120. progress.setValue(1);
  121. qApp->processEvents();
  122. // Do something
  123.  
  124. progress.setLabelText("Doing something else (2).");
  125. progress.setValue(1);
  126. qApp->processEvents();
  127. // Do something
  128.  
  129. // And so on...
  130.  
  131. progress.setValue(5);
  132. qApp->processEvents();
  133. progress.close();
  134.  
  135. QApplication::restoreOverrideCursor();
  136. }
  137. void MainWindow::on_actionExit_triggered()
  138. {
  139. close();
  140. }
  141.  
  142. void MainWindow::SearchFiles(const QString &start_path, QStringList &File_list)
  143. {
  144. QString targetfile("config.xml"); // Put here the filename you may want to test
  145. QString iparameters_fich = QDir::toNativeSeparators(start_path + '/' + targetfile);
  146. if (QFile(iparameters_fich).exists())
  147. File_list << iparameters_fich;
  148. else
  149. {
  150.  
  151. // Search configuration files in subdirectories
  152. QStringList nameFilter;
  153. QFileInfoList lstDirectoriesInfo =
  154. QDir(start_path).entryInfoList(nameFilter,
  155. QDir::NoDotAndDotDot | QDir::Dirs,
  156. QDir::Name);
  157. for (int i = 0; (i < lstDirectoriesInfo.size()); i++)
  158. SearchFiles(lstDirectoriesInfo.at(i).absoluteFilePath(), File_list);
  159. }
  160. }
To copy to clipboard, switch view to plain text mode 


Regarding the QProgressDialog, I've tried to implement modal and non-modal, and I've also tried with different values: 0, 1 and no value. The result is the same in all cases.

Thanks a lot in advance. Regards,

jcbaraza