Progress Bar: Difference between revisions

From Qt Wiki
Jump to navigation Jump to search
No edit summary
No edit summary
Line 8: Line 8:
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 [http://doc.qt.io/qt-5/qobject.html QObject] 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.
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 [http://doc.qt.io/qt-5/qobject.html QObject] 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 [http://developer.qt.nokia.com/doc/qt-4.8/qfuturewatcher.html QFutureWatcher] and [http://doc.qt.io/qt-5/qtconcurrentrun.html QtConcurrent::run()], this is extremely easy. Below we demonstrate how to use this technique with both a [http://doc.qt.io/qt-5/qprogressdialog.html QProgressDialog] and a [http://doc.qt.io/qt-5/qprogressbar.html QProgressBar].
However, using [http://doc.qt.io/qt-5/qfuturewatcher.html QFutureWatcher] and [http://doc.qt.io/qt-5/qtconcurrentrun.html QtConcurrent::run()], this is extremely easy. Below we demonstrate how to use this technique with both a [http://doc.qt.io/qt-5/qprogressdialog.html QProgressDialog] and a [http://doc.qt.io/qt-5/qprogressbar.html QProgressBar].


== QProgressBar Example ==
== QProgressBar Example ==

Revision as of 06:56, 13 April 2015



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 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 and QtConcurrent::run(), this is extremely easy. Below we demonstrate how to use this technique with both a QProgressDialog and a QProgressBar.

QProgressBar Example

form.h

#ifndef FORM_H
#define FORM_H

#include "ui_form.h"

#include <QFutureWatcher>

#include "MyClass.h"

class Form : public QWidget, private Ui::Form
{
Q_OBJECT

public slots:

void slot_finished();
 void on_pushButton_clicked();

public:
 Form(QWidget *parent = 0);

private:
 QFutureWatcher<void> FutureWatcher;
 MyClass MyObject;
};

#endif

form.cpp

#include <QtGui>
#include <QImage>

#include "form.h"

#include <iostream>

Form::Form(QWidget *parent)
 : QWidget(parent)
{
 setupUi(this);

this->progressBar->setMinimum(0);
 this->progressBar->setMaximum(0);
 this->progressBar->hide();

connect(&this->FutureWatcher, SIGNAL (finished()), this, SLOT (slot_finished()));

}

void Form::slot_finished()
{
 this->progressBar->hide();
}

void Form::on_pushButton_clicked()
{
 this->progressBar->show();

// Start the computation.
 QFuture<void> future = QtConcurrent::run(&this->MyObject, &MyClass::LongFunction);
 this->FutureWatcher.setFuture(future);
}

form.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Form</class>
 <widget class="QWidget" name="Form">
 <property name="geometry">
 <rect>
 <x>0</x>
 <y>0</y>
 <width>400</width>
 <height>300</height>
 </rect>
 </property>
 <property name="windowTitle">
 <string>Form</string>
 </property>
 <layout class="QVBoxLayout" name="verticalLayout">
 <item>
 <widget class="QPushButton" name="pushButton">
 <property name="text">
 <string>PushButton</string>
 </property>
 </widget>
 </item>
 <item>
 <widget class="QLineEdit" name="lineEdit"/>
 </item>
 <item>
 <widget class="QProgressBar" name="progressBar">
 <property name="value">
 <number>24</number>
 </property>
 </widget>
 </item>
 </layout>
 </widget>
 <resources/>
 <connections/>
</ui>

FutureWatcher.cpp

#include <QApplication>
#include <QObject>
#include <QThread>

#include <iostream>

#include "form.h"

int main(int argc, char*argv[])
{
 QApplication app(argc, argv);

Form form;

form.show();

return app.exec();
}

MyClass.h

#ifndef MyClass_H
#define MyClass_H

#include <iostream>

class MyClass
{
public:

void LongFunction()
 {
 for( int count = 0; count < 5; count++ )
 {
 sleep( 1 );
 std::cout << "Ping long!" << std::endl;
 }
 }
};

#endif

CMakeLists.txt

cmake_minimum_required(VERSION 2.6)

PROJECT (FutureWatcher)

FIND_PACKAGE(Qt4 REQUIRED)
INCLUDE (${QT_USE_FILE})

QT4_WRAP_CPP(MOCSrcs form.h)
QT4_WRAP_UI(UISrcs form.ui)

include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})

ADD_EXECUTABLE(FutureWatcher FutureWatcher.cpp MyClass.cpp form.cpp ${MOCSrcs} ${UISrcs})
TARGET_LINK_LIBRARIES(FutureWatcher ${QT_LIBRARIES})

QProgressDialog Example

form.h

#ifndef FORM_H
#define FORM_H

#include "ui_form.h"

#include <QFutureWatcher>

#include "MyClass.h"

class QProgressDialog;

class Form : public QWidget, private Ui::Form
{
Q_OBJECT

public slots:

void slot_finished();
 void on_pushButton_clicked();

public:
 Form(QWidget '''parent = 0);

private:
 QFutureWatcher<void> FutureWatcher;
 MyClass MyObject;
 QProgressDialog''' ProgressDialog;
};

#endif

form.cpp

#include <QtGui>
#include <QImage>

#include "form.h"

#include <iostream>

Form::Form(QWidget *parent)
 : QWidget(parent)
{
 setupUi(this);

this->ProgressDialog = new QProgressDialog(this);

connect(&this->FutureWatcher, SIGNAL (finished()), this, SLOT (slot_finished()));
 connect(&this->FutureWatcher, SIGNAL (finished()), this->ProgressDialog , SLOT (cancel()));

}

void Form::slot_finished()
{
 std::cout << "Finshed" << std::endl;
}

void Form::on_pushButton_clicked()
{
 // Start the computation.
 QFuture<void> future = QtConcurrent::run(&this->MyObject, &MyClass::LongFunction);
 this->FutureWatcher.setFuture(future);

this->ProgressDialog->setMinimum(0);
 this->ProgressDialog->setMaximum(0);
 this->ProgressDialog->setWindowModality(Qt::WindowModal);
 this->ProgressDialog->exec();

}

form.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Form</class>
 <widget class="QWidget" name="Form">
 <property name="geometry">
 <rect>
 <x>0</x>
 <y>0</y>
 <width>400</width>
 <height>300</height>
 </rect>
 </property>
 <property name="windowTitle">
 <string>Form</string>
 </property>
 <layout class="QVBoxLayout" name="verticalLayout">
 <item>
 <widget class="QPushButton" name="pushButton">
 <property name="text">
 <string>PushButton</string>
 </property>
 </widget>
 </item>
 </layout>
 </widget>
 <resources/>
 <connections/>
</ui>

MyClass.h

#ifndef MyClass_H
#define MyClass_H

#include <iostream>

class MyClass
{
public:

void LongFunction()
 {
 for( int count = 0; count < 5; count++ )
 {
 sleep( 1 );
 std::cout << "Ping long!" << std::endl;
 }
 }
};

#endif

FutureWatcherProgressDialog.cpp

#include <QApplication>

  1. include <QObject>
  2. include <QThread>
  1. include <iostream>
  1. include "form.h"

int main(int argc, char*argv[]) {

QApplication app(argc, argv);

Form form;

form.show();

return app.exec();