Progress Bar

It is often necessary to display a progress bar while a long operation is happening. The case we are concerned about in this example is when there is no easy way to track the progress of the operation – all that is known is when it is done. There are many ways to do this. You could use a progressBar widget on your widget and run the operation in a different thread (using moveToThread()). This typically requires a special object to be created (a subclass of QObject [developer.qt.nokia.com] that runs the operation and then emits a finished() signal), which can be a pain if you need to do this for many different operations.

However, using QFutureWatcher [developer.qt.nokia.com] and QtConcurrent::run() [developer.qt.nokia.com], this is extremely easy. Below we demonstrate how to use this technique with both a QProgressDialog and a QProgressBar.

QProgressBar Example

form.h

  1. #ifndef FORM_H
  2. #define FORM_H
  3.  
  4. #include "ui_form.h"
  5.  
  6. #include <QFutureWatcher>
  7.  
  8. #include "MyClass.h"
  9.  
  10. class Form : public QWidget, private Ui::Form
  11. {
  12. Q_OBJECT
  13.  
  14. public slots:
  15.  
  16.   void slot_finished();
  17.   void on_pushButton_clicked();
  18.  
  19. public:
  20.     Form(QWidget *parent = 0);
  21.  
  22. private:
  23.   QFutureWatcher<void> FutureWatcher;
  24.   MyClass MyObject;
  25. };
  26.  
  27. #endif

form.cpp

  1. #include <QtGui>
  2. #include <QImage>
  3.  
  4. #include "form.h"
  5.  
  6. #include <iostream>
  7.  
  8. Form::Form(QWidget *parent)
  9.     : QWidget(parent)
  10. {
  11.   setupUi(this);
  12.  
  13.   this->progressBar->setMinimum(0);
  14.   this->progressBar->setMaximum(0);
  15.   this->progressBar->hide();
  16.  
  17.  
  18.   connect(&this->FutureWatcher, SIGNAL(finished()), this, SLOT(slot_finished()));
  19.  
  20. }
  21.  
  22. void Form::slot_finished()
  23. {
  24.   this->progressBar->hide();
  25. }
  26.  
  27. void Form::on_pushButton_clicked()
  28. {
  29.   this->progressBar->show();
  30.  
  31.   // Start the computation.
  32.   QFuture<void> future = QtConcurrent::run(&this->MyObject, &MyClass::LongFunction);
  33.   this->FutureWatcher.setFuture(future);
  34. }

form.ui

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <ui version="4.0">
  3.  <class>Form</class>
  4.  <widget class="QWidget" name="Form">
  5.   <property name="geometry">
  6.    <rect>
  7.     <x>0</x>
  8.     <y>0</y>
  9.     <width>400</width>
  10.     <height>300</height>
  11.    </rect>
  12.   </property>
  13.   <property name="windowTitle">
  14.    <string>Form</string>
  15.   </property>
  16.   <layout class="QVBoxLayout" name="verticalLayout">
  17.    <item>
  18.     <widget class="QPushButton" name="pushButton">
  19.      <property name="text">
  20.       <string>PushButton</string>
  21.      </property>
  22.     </widget>
  23.    </item>
  24.    <item>
  25.     <widget class="QLineEdit" name="lineEdit"/>
  26.    </item>
  27.    <item>
  28.     <widget class="QProgressBar" name="progressBar">
  29.      <property name="value">
  30.       <number>24</number>
  31.      </property>
  32.     </widget>
  33.    </item>
  34.   </layout>
  35.  </widget>
  36.  <resources/>
  37.  <connections/>
  38. </ui>

FutureWatcher.cpp

  1. #include <QApplication>
  2. #include <QObject>
  3. #include <QThread>
  4.  
  5. #include <iostream>
  6.  
  7. #include "form.h"
  8.  
  9. int main(int argc, char*argv[])
  10. {
  11.   QApplication app(argc, argv);
  12.  
  13.   Form form;
  14.  
  15.   form.show();
  16.  
  17.   return app.exec();
  18. }

MyClass.h

  1. #ifndef MyClass_H
  2. #define MyClass_H
  3.  
  4. #include <iostream>
  5.  
  6. class MyClass
  7. {
  8. public:
  9.  
  10.   void LongFunction()
  11.   {
  12.     for( int count = 0; count < 5; count++ )
  13.     {
  14.       sleep( 1 );
  15.       std::cout << "Ping long!" << std::endl;
  16.     }
  17.   }
  18. };
  19.  
  20. #endif

CMakeLists.txt

  1. cmake_minimum_required(VERSION 2.6)
  2.  
  3. PROJECT(FutureWatcher)
  4.  
  5. FIND_PACKAGE(Qt4 REQUIRED)
  6. INCLUDE(${QT_USE_FILE})
  7.  
  8. QT4_WRAP_CPP(MOCSrcs form.h)
  9. QT4_WRAP_UI(UISrcs form.ui)
  10.  
  11. include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
  12.  
  13. ADD_EXECUTABLE(FutureWatcher FutureWatcher.cpp MyClass.cpp form.cpp ${MOCSrcs} ${UISrcs})
  14. TARGET_LINK_LIBRARIES(FutureWatcher ${QT_LIBRARIES})

QProgressDialog Example

form.h

  1. #ifndef FORM_H
  2. #define FORM_H
  3.  
  4. #include "ui_form.h"
  5.  
  6. #include <QFutureWatcher>
  7.  
  8. #include "MyClass.h"
  9.  
  10. class QProgressDialog;
  11.  
  12. class Form : public QWidget, private Ui::Form
  13. {
  14. Q_OBJECT
  15.  
  16. public slots:
  17.  
  18.   void slot_finished();
  19.   void on_pushButton_clicked();
  20.  
  21. public:
  22.     Form(QWidget *parent = 0);
  23.  
  24. private:
  25.   QFutureWatcher<void> FutureWatcher;
  26.   MyClass MyObject;
  27.   QProgressDialog* ProgressDialog;
  28. };
  29.  
  30. #endif

form.cpp

  1. #include <QtGui>
  2. #include <QImage>
  3.  
  4. #include "form.h"
  5.  
  6. #include <iostream>
  7.  
  8. Form::Form(QWidget *parent)
  9.     : QWidget(parent)
  10. {
  11.   setupUi(this);
  12.  
  13.   this->ProgressDialog = new QProgressDialog();
  14.  
  15.   connect(&this->FutureWatcher, SIGNAL(finished()), this, SLOT(slot_finished()));
  16.   connect(&this->FutureWatcher, SIGNAL(finished()), this->ProgressDialog , SLOT(cancel()));
  17.  
  18. }
  19.  
  20. void Form::slot_finished()
  21. {
  22.   std::cout << "Finshed" << std::endl;
  23. }
  24.  
  25. void Form::on_pushButton_clicked()
  26. {
  27.   // Start the computation.
  28.   QFuture<void> future = QtConcurrent::run(&this->MyObject, &MyClass::LongFunction);
  29.   this->FutureWatcher.setFuture(future);
  30.  
  31.   this->ProgressDialog->setMinimum(0);
  32.   this->ProgressDialog->setMaximum(0);
  33.   this->ProgressDialog->setWindowModality(Qt::WindowModal);
  34.   this->ProgressDialog->exec();
  35.  
  36. }

form.ui

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <ui version="4.0">
  3.  <class>Form</class>
  4.  <widget class="QWidget" name="Form">
  5.   <property name="geometry">
  6.    <rect>
  7.     <x>0</x>
  8.     <y>0</y>
  9.     <width>400</width>
  10.     <height>300</height>
  11.    </rect>
  12.   </property>
  13.   <property name="windowTitle">
  14.    <string>Form</string>
  15.   </property>
  16.   <layout class="QVBoxLayout" name="verticalLayout">
  17.    <item>
  18.     <widget class="QPushButton" name="pushButton">
  19.      <property name="text">
  20.       <string>PushButton</string>
  21.      </property>
  22.     </widget>
  23.    </item>
  24.   </layout>
  25.  </widget>
  26.  <resources/>
  27.  <connections/>
  28. </ui>

MyClass.h

  1. #ifndef MyClass_H
  2. #define MyClass_H
  3.  
  4. #include <iostream>
  5.  
  6. class MyClass
  7. {
  8. public:
  9.  
  10.   void LongFunction()
  11.   {
  12.     for( int count = 0; count < 5; count++ )
  13.     {
  14.       sleep( 1 );
  15.       std::cout << "Ping long!" << std::endl;
  16.     }
  17.   }
  18. };
  19.  
  20.  
  21. #endif

FutureWatcherProgressDialog.cpp

  1. #include <QApplication>
  2. #include <QObject>
  3. #include <QThread>
  4.  
  5. #include <iostream>
  6.  
  7. #include "form.h"
  8.  
  9. int main(int argc, char*argv[])
  10. {
  11.   QApplication app(argc, argv);
  12.  
  13.   Form form;
  14.  
  15.   form.show();
  16.  
  17.   return app.exec();
  18. }

Categories: