Example: rename progressdialog to primecounter and modernize it
The previous example finished way too quickly and provided no real value in regards to API understanding. Previously, QtConcurrent::map was used, which was also used in other examples. We are now using QtConcurrent::filterReduce to demonstrate other functionality. Task-number: QTBUG-111165 Pick-to: 6.5 6.5.0 Change-Id: Ibd6eb119d0711cddfe8b211d460e9d67d6ce95c3 Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io> Reviewed-by: Ivan Solovev <ivan.solovev@qt.io>
This commit is contained in:
parent
4a9696aa05
commit
8352756d27
@ -40,7 +40,6 @@ manifestmeta.android.names = "Qt3D/Qt 3D: Basic Shapes C++ Example" \
|
||||
"QtBluetooth/Bluetooth Scanner Example" \
|
||||
"QtBluetooth/QML Bluetooth Scanner Example" \
|
||||
"QtCharts/*" \
|
||||
"QtConcurrent/QtConcurrent Progress Dialog Example" \
|
||||
"QtDataVisualization/Audiolevels Example" \
|
||||
"QtDataVisualization/Qt Quick 2 Scatter Example" \
|
||||
"QtDataVisualization/Qt Quick 2 Surface Multiseries Example" \
|
||||
|
@ -6,6 +6,6 @@ if(NOT TARGET Qt6::Concurrent)
|
||||
endif()
|
||||
if(TARGET Qt6::Widgets)
|
||||
qt_internal_add_example(imagescaling)
|
||||
qt_internal_add_example(progressdialog)
|
||||
qt_internal_add_example(primecounter)
|
||||
qt_internal_add_example(wordcount)
|
||||
endif()
|
||||
|
@ -1,36 +1,39 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# Copyright (C) 2023 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(progressdialog LANGUAGES CXX)
|
||||
project(primecounter LANGUAGES CXX)
|
||||
|
||||
if(NOT DEFINED INSTALL_EXAMPLESDIR)
|
||||
set(INSTALL_EXAMPLESDIR "examples")
|
||||
endif()
|
||||
|
||||
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/qtconcurrent/progressdialog")
|
||||
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/qtconcurrent/primecounter")
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Concurrent Core Gui Widgets)
|
||||
|
||||
qt_standard_project_setup()
|
||||
|
||||
qt_add_executable(progressdialog
|
||||
qt_add_executable(primecounter
|
||||
main.cpp
|
||||
primecounter.ui
|
||||
primecounter.cpp
|
||||
primecounter.h
|
||||
)
|
||||
|
||||
set_target_properties(progressdialog PROPERTIES
|
||||
WIN32_EXECUTABLE FALSE
|
||||
set_target_properties(primecounter PROPERTIES
|
||||
WIN32_EXECUTABLE TRUE
|
||||
MACOSX_BUNDLE TRUE
|
||||
)
|
||||
|
||||
target_link_libraries(progressdialog PRIVATE
|
||||
target_link_libraries(primecounter PRIVATE
|
||||
Qt6::Concurrent
|
||||
Qt6::Core
|
||||
Qt6::Gui
|
||||
Qt6::Widgets
|
||||
)
|
||||
|
||||
install(TARGETS progressdialog
|
||||
install(TARGETS primecounter
|
||||
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
|
BIN
examples/qtconcurrent/primecounter/doc/images/primecounter.png
Normal file
BIN
examples/qtconcurrent/primecounter/doc/images/primecounter.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.5 KiB |
@ -0,0 +1,88 @@
|
||||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example primecounter
|
||||
\meta tags {widgets, threads}
|
||||
\title Prime Counter
|
||||
\ingroup qtconcurrentexamples
|
||||
\brief Demonstrates how to monitor the progress of concurrent operations.
|
||||
|
||||
The following example demonstrates how to create an interactive and
|
||||
non-blocking QtWidgets application using the QFutureWatcher class and the
|
||||
\l {Concurrent Filter-Reduce} {filteredReduced} functions from
|
||||
\l {Qt Concurrent}. With this example, the user can create a QList of
|
||||
integers that can be resized. The list will be automatically filled with
|
||||
natural numbers starting from 1 up to n. The program will then check for
|
||||
prime numbers within the list and display the total count of prime numbers
|
||||
found.
|
||||
|
||||
\image primecounter.png
|
||||
|
||||
\include examples-run.qdocinc
|
||||
|
||||
\section1 Setting up the connections
|
||||
|
||||
The \l {Qt Concurrent} library provides the
|
||||
\l {Concurrent Filter-Reduce} {filteredReduced} functions, which can operate
|
||||
in two modes:
|
||||
\l {QtConcurrent::ReduceOption} {OrderedReduce and UnorderedReduce}. In
|
||||
\c OrderedReduce mode, the reducing function is called in the order of the
|
||||
original sequence, whereas in \c UnorderedReduce mode, the elements are
|
||||
accessed randomly.
|
||||
|
||||
After configuring the UI with the desired elements, it is necessary to
|
||||
connect them to the signals of the concurrent operations using the Qt
|
||||
\l {Signals & Slots} mechanism. In this example, we use the QFutureWatcher
|
||||
class to monitor the progress of the concurrent operations and provide the
|
||||
signals required to implement the interactive GUI.
|
||||
|
||||
\dots
|
||||
\snippet primecounter/primecounter.cpp 1
|
||||
\dots
|
||||
|
||||
The QFutureWatcher class plays a vital role in this example as it provides
|
||||
the signals required to update the UI in response to changes in the
|
||||
concurrent operations.
|
||||
|
||||
\section1 Starting the concurrent operation
|
||||
|
||||
After connecting all the \l {Signals & Slots}, and when the user presses
|
||||
the QPushButton, the \c {start()} function is called.
|
||||
|
||||
In the \c {start()} function, we call the
|
||||
\l {Concurrent Filter-Reduce} {filteredReduced} function from Qt Concurrent
|
||||
and set the future on the QFutureWatcher member. To ensure that this
|
||||
operation runs truly concurrently, we specify a separate QThreadPool as the
|
||||
first parameter. This approach also avoids any possible blocking in the
|
||||
global thread pool. We pass the QList of integers as the container, a
|
||||
static filter and reduce function, and finally the
|
||||
\l {QtConcurrent::} {ReduceOption} flag.
|
||||
|
||||
\dots
|
||||
\snippet primecounter/primecounter.cpp 2
|
||||
\dots
|
||||
|
||||
Let's examine the filter and reduce functions. These functions are declared
|
||||
static in this example since they do not depend on any member variable.
|
||||
However, they could easily be specified as lambdas or member functions.
|
||||
|
||||
The filter function marks elements for subsequent reduction with the reduce
|
||||
function. This implementation is a simple prime filter. As this function
|
||||
takes a const reference as an argument, it allows thread-safe operation on
|
||||
the container it operates on.
|
||||
|
||||
\dots
|
||||
\snippet primecounter/primecounter.cpp 3
|
||||
\dots
|
||||
|
||||
The reduce function takes a modifiable reference of the same type as the
|
||||
container it operates on as its first parameter. The second parameter is the
|
||||
previously filtered element from the filter function. In this example, we
|
||||
count the number of primes.
|
||||
|
||||
\dots
|
||||
\snippet primecounter/primecounter.cpp 4
|
||||
\dots
|
||||
|
||||
*/
|
18
examples/qtconcurrent/primecounter/main.cpp
Normal file
18
examples/qtconcurrent/primecounter/main.cpp
Normal file
@ -0,0 +1,18 @@
|
||||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include <QtWidgets/qapplication.h>
|
||||
#include "primecounter.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
app.setOrganizationName("QtProject");
|
||||
app.setApplicationName(QApplication::translate("main", "Prime Counter"));
|
||||
|
||||
PrimeCounter dialog;
|
||||
dialog.setWindowTitle(QApplication::translate("main", "Prime Counter"));
|
||||
dialog.show();
|
||||
|
||||
return app.exec();
|
||||
}
|
139
examples/qtconcurrent/primecounter/primecounter.cpp
Normal file
139
examples/qtconcurrent/primecounter/primecounter.cpp
Normal file
@ -0,0 +1,139 @@
|
||||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "primecounter.h"
|
||||
#include "ui_primecounter.h"
|
||||
|
||||
PrimeCounter::PrimeCounter(QWidget *parent)
|
||||
: QDialog(parent), stepSize(100000), ui(setupUi())
|
||||
{
|
||||
// Control the concurrent operation with the QFutureWatcher
|
||||
//! [1]
|
||||
connect(ui->pushButton, &QPushButton::clicked,
|
||||
this, [this] { start(); });
|
||||
connect(&watcher, &QFutureWatcher<Element>::finished,
|
||||
this, [this] { finish(); });
|
||||
connect(&watcher, &QFutureWatcher<Element>::progressRangeChanged,
|
||||
ui->progressBar, &QProgressBar::setRange);
|
||||
connect(&watcher, &QFutureWatcher<Element>::progressValueChanged,
|
||||
ui->progressBar, &QProgressBar::setValue);
|
||||
//! [1]
|
||||
}
|
||||
|
||||
PrimeCounter::~PrimeCounter()
|
||||
{
|
||||
watcher.cancel();
|
||||
delete ui;
|
||||
}
|
||||
|
||||
//! [3]
|
||||
bool PrimeCounter::filterFunction(const Element &element)
|
||||
{
|
||||
// Filter for primes
|
||||
if (element <= 1)
|
||||
return false;
|
||||
for (Element i = 2; i*i <= element; ++i) {
|
||||
if (element % i == 0)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//! [3]
|
||||
|
||||
//! [4]
|
||||
void PrimeCounter::reduceFunction(Element &out, const Element &value)
|
||||
{
|
||||
// Count the amount of primes.
|
||||
Q_UNUSED(value);
|
||||
++out;
|
||||
}
|
||||
//! [4]
|
||||
|
||||
//! [2]
|
||||
void PrimeCounter::start()
|
||||
{
|
||||
if (ui->pushButton->isChecked()) {
|
||||
ui->comboBox->setEnabled(false);
|
||||
ui->pushButton->setText(tr("Cancel"));
|
||||
ui->labelResult->setText(tr("Calculating ..."));
|
||||
ui->labelFilter->setText(tr("Selected Reduce Option: %1").arg(ui->comboBox->currentText()));
|
||||
fillElementList(ui->horizontalSlider->value() * stepSize);
|
||||
|
||||
timer.start();
|
||||
watcher.setFuture(
|
||||
QtConcurrent::filteredReduced(
|
||||
&pool,
|
||||
elementList,
|
||||
filterFunction,
|
||||
reduceFunction,
|
||||
currentReduceOpt | QtConcurrent::SequentialReduce));
|
||||
//! [2]
|
||||
} else {
|
||||
watcher.cancel();
|
||||
ui->progressBar->setValue(0);
|
||||
ui->comboBox->setEnabled(true);
|
||||
ui->labelResult->setText(tr(""));
|
||||
ui->pushButton->setText(tr("Start"));
|
||||
ui->labelFilter->setText(tr("Operation Canceled"));
|
||||
}
|
||||
}
|
||||
|
||||
void PrimeCounter::finish()
|
||||
{
|
||||
// The finished signal from the QFutureWatcher is also emitted when cancelling.
|
||||
if (watcher.isCanceled())
|
||||
return;
|
||||
|
||||
auto elapsedTime = timer.elapsed();
|
||||
ui->progressBar->setValue(0);
|
||||
ui->comboBox->setEnabled(true);
|
||||
ui->pushButton->setChecked(false);
|
||||
ui->pushButton->setText(tr("Start"));
|
||||
ui->labelFilter->setText(
|
||||
tr("Filter '%1' took %2 ms to calculate").arg(ui->comboBox->currentText())
|
||||
.arg(elapsedTime));
|
||||
ui->labelResult->setText(
|
||||
tr("Found %1 primes in the range of elements").arg(watcher.result()));
|
||||
}
|
||||
|
||||
void PrimeCounter::fillElementList(unsigned int count)
|
||||
{
|
||||
// Fill elementList with values from [1, count] when starting the calculations.
|
||||
auto prevSize = elementList.size();
|
||||
if (prevSize == count)
|
||||
return; // Nothing to do here.
|
||||
|
||||
auto startVal = elementList.empty() ? 1 : elementList.back() + 1;
|
||||
elementList.resize(count);
|
||||
if (elementList.begin() + prevSize < elementList.end())
|
||||
std::iota(elementList.begin() + prevSize, elementList.end(), startVal);
|
||||
}
|
||||
|
||||
Ui::PrimeCounter* PrimeCounter::setupUi()
|
||||
{
|
||||
Ui::PrimeCounter *setupUI = new Ui::PrimeCounter;
|
||||
setupUI->setupUi(this);
|
||||
setModal(true);
|
||||
|
||||
// Set up the slider
|
||||
connect(setupUI->horizontalSlider, &QSlider::valueChanged,
|
||||
this, [setupUI, this] (const int &pos) {
|
||||
setupUI->labelResult->setText("");
|
||||
setupUI->labelSize->setText(tr("Elements in list: %1").arg(pos * stepSize));
|
||||
});
|
||||
setupUI->horizontalSlider->setValue(30);
|
||||
|
||||
// Set up the combo box
|
||||
setupUI->comboBox->insertItem(0, tr("Unordered Reduce"), QtConcurrent::UnorderedReduce);
|
||||
setupUI->comboBox->insertItem(1, tr("Ordered Reduce"), QtConcurrent::OrderedReduce);
|
||||
|
||||
auto comboBoxChange = [this, setupUI](int pos) {
|
||||
currentReduceOpt = setupUI->comboBox->itemData(pos).value<QtConcurrent::ReduceOptions>();
|
||||
setupUI->labelFilter->setText(tr("Selected Reduce Option: %1")
|
||||
.arg(setupUI->comboBox->currentText()));
|
||||
};
|
||||
comboBoxChange(setupUI->comboBox->currentIndex());
|
||||
connect(setupUI->comboBox, &QComboBox::currentIndexChanged, this, comboBoxChange);
|
||||
|
||||
return setupUI;
|
||||
}
|
49
examples/qtconcurrent/primecounter/primecounter.h
Normal file
49
examples/qtconcurrent/primecounter/primecounter.h
Normal file
@ -0,0 +1,49 @@
|
||||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef PRIMECOUNTER_H
|
||||
#define PRIMECOUNTER_H
|
||||
|
||||
#include <QtWidgets/qdialog.h>
|
||||
#include <QtCore/qfuturewatcher.h>
|
||||
#include <QtConcurrent/qtconcurrentfilter.h>
|
||||
#include <QtConcurrent/qtconcurrentreducekernel.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QLabel;
|
||||
class QProgressBar;
|
||||
namespace Ui {
|
||||
class PrimeCounter;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class PrimeCounter : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
using Element = unsigned long long;
|
||||
public:
|
||||
explicit PrimeCounter(QWidget* parent = nullptr);
|
||||
~PrimeCounter() override;
|
||||
|
||||
private:
|
||||
static bool filterFunction(const Element &element);
|
||||
static void reduceFunction(Element &out, const Element &value);
|
||||
void fillElementList(unsigned int count);
|
||||
Ui::PrimeCounter* setupUi();
|
||||
|
||||
private slots:
|
||||
void start();
|
||||
void finish();
|
||||
|
||||
private:
|
||||
QList<Element> elementList;
|
||||
QFutureWatcher<Element> watcher;
|
||||
QtConcurrent::ReduceOptions currentReduceOpt;
|
||||
QElapsedTimer timer;
|
||||
QThreadPool pool;
|
||||
unsigned int stepSize;
|
||||
Ui::PrimeCounter *ui;
|
||||
};
|
||||
|
||||
#endif //PRIMECOUNTER_H
|
9
examples/qtconcurrent/primecounter/primecounter.pro
Normal file
9
examples/qtconcurrent/primecounter/primecounter.pro
Normal file
@ -0,0 +1,9 @@
|
||||
QT += concurrent widgets
|
||||
|
||||
SOURCES += main.cpp primecounter.cpp
|
||||
HEADERS += primecounter.h
|
||||
|
||||
target.path = $$[QT_INSTALL_EXAMPLES]/qtconcurrent/primecounter
|
||||
INSTALLS += target
|
||||
|
||||
FORMS += primecounter.ui
|
177
examples/qtconcurrent/primecounter/primecounter.ui
Normal file
177
examples/qtconcurrent/primecounter/primecounter.ui
Normal file
@ -0,0 +1,177 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>PrimeCounter</class>
|
||||
<widget class="QDialog" name="PrimeCounter">
|
||||
<property name="windowModality">
|
||||
<enum>Qt::WindowModal</enum>
|
||||
</property>
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>454</width>
|
||||
<height>320</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Dialog</string>
|
||||
</property>
|
||||
<property name="autoFillBackground">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<property name="leftMargin">
|
||||
<number>20</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>20</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>20</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>20</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="labelInfo">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>11</pointsize>
|
||||
<bold>false</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Select a reducing option and measure the speed</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer1">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>30</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout2">
|
||||
<property name="topMargin">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QComboBox" name="comboBox"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout1">
|
||||
<property name="topMargin">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton">
|
||||
<property name="text">
|
||||
<string>Start</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QProgressBar" name="progressBar">
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="labelFilter">
|
||||
<property name="text">
|
||||
<string>Filter Label</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout3">
|
||||
<item>
|
||||
<widget class="QSlider" name="horizontalSlider">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="labelSize">
|
||||
<property name="text">
|
||||
<string>size</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="indent">
|
||||
<number>10</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="labelResult">
|
||||
<property name="text">
|
||||
<string>Result Label</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
Binary file not shown.
Before Width: | Height: | Size: 4.5 KiB |
@ -1,14 +0,0 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example progressdialog
|
||||
\title QtConcurrent Progress Dialog Example
|
||||
\brief Demonstrates how to monitor the progress of the active processes.
|
||||
\ingroup qtconcurrentexamples
|
||||
|
||||
The QtConcurrent Progress Dialog example shows how to use the
|
||||
QFutureWatcher class to monitor the progress of a long-running operation.
|
||||
|
||||
\image qtconcurrent-progressdialog.png
|
||||
*/
|
@ -1,53 +0,0 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include <QtWidgets>
|
||||
#include <QtConcurrent>
|
||||
|
||||
#include <functional>
|
||||
|
||||
using namespace QtConcurrent;
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
|
||||
const int iterations = 20;
|
||||
|
||||
// Prepare the list.
|
||||
QList<int> list;
|
||||
for (int i = 0; i < iterations; ++i)
|
||||
list.append(i);
|
||||
|
||||
// Create a progress dialog.
|
||||
QProgressDialog dialog;
|
||||
dialog.setLabelText(QString("Progressing using %1 thread(s)...").arg(QThread::idealThreadCount()));
|
||||
|
||||
// Create a QFutureWatcher and connect signals and slots.
|
||||
QFutureWatcher<void> futureWatcher;
|
||||
QObject::connect(&futureWatcher, &QFutureWatcher<void>::finished, &dialog, &QProgressDialog::reset);
|
||||
QObject::connect(&dialog, &QProgressDialog::canceled, &futureWatcher, &QFutureWatcher<void>::cancel);
|
||||
QObject::connect(&futureWatcher, &QFutureWatcher<void>::progressRangeChanged, &dialog, &QProgressDialog::setRange);
|
||||
QObject::connect(&futureWatcher, &QFutureWatcher<void>::progressValueChanged, &dialog, &QProgressDialog::setValue);
|
||||
|
||||
// Our function to compute
|
||||
std::function<void(int&)> spin = [](int &iteration) {
|
||||
const int work = 1000 * 1000 * 40;
|
||||
volatile int v = 0;
|
||||
for (int j = 0; j < work; ++j)
|
||||
++v;
|
||||
|
||||
qDebug() << "iteration" << iteration << "in thread" << QThread::currentThreadId();
|
||||
};
|
||||
|
||||
// Start the computation.
|
||||
futureWatcher.setFuture(QtConcurrent::map(list, spin));
|
||||
|
||||
// Display the dialog and start the event loop.
|
||||
dialog.exec();
|
||||
|
||||
futureWatcher.waitForFinished();
|
||||
|
||||
// Query the future to check if was canceled.
|
||||
qDebug() << "Canceled?" << futureWatcher.future().isCanceled();
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
QT += concurrent widgets
|
||||
CONFIG += console
|
||||
|
||||
SOURCES += main.cpp
|
||||
|
||||
target.path = $$[QT_INSTALL_EXAMPLES]/qtconcurrent/progressdialog
|
||||
INSTALLS += target
|
@ -2,12 +2,12 @@ requires(qtHaveModule(concurrent))
|
||||
|
||||
TEMPLATE = subdirs
|
||||
SUBDIRS = imagescaling \
|
||||
progressdialog \
|
||||
primecounter \
|
||||
wordcount
|
||||
|
||||
!qtHaveModule(widgets) {
|
||||
SUBDIRS -= \
|
||||
imagescaling \
|
||||
progressdialog \
|
||||
primecounter \
|
||||
wordcount
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user