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 Change-Id: Ibd6eb119d0711cddfe8b211d460e9d67d6ce95c3 Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io> Reviewed-by: Ivan Solovev <ivan.solovev@qt.io> (cherry picked from commit 8352756d27e5657390b6e87f45e0c0bae6b7784e) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
parent
6ea0d57565
commit
e453de0c0b
@ -40,7 +40,6 @@ manifestmeta.android.names = "Qt3D/Qt 3D: Basic Shapes C++ Example" \
|
|||||||
"QtBluetooth/Bluetooth Scanner Example" \
|
"QtBluetooth/Bluetooth Scanner Example" \
|
||||||
"QtBluetooth/QML Bluetooth Scanner Example" \
|
"QtBluetooth/QML Bluetooth Scanner Example" \
|
||||||
"QtCharts/*" \
|
"QtCharts/*" \
|
||||||
"QtConcurrent/QtConcurrent Progress Dialog Example" \
|
|
||||||
"QtDataVisualization/Audiolevels Example" \
|
"QtDataVisualization/Audiolevels Example" \
|
||||||
"QtDataVisualization/Qt Quick 2 Scatter Example" \
|
"QtDataVisualization/Qt Quick 2 Scatter Example" \
|
||||||
"QtDataVisualization/Qt Quick 2 Surface Multiseries Example" \
|
"QtDataVisualization/Qt Quick 2 Surface Multiseries Example" \
|
||||||
|
@ -6,6 +6,6 @@ if(NOT TARGET Qt6::Concurrent)
|
|||||||
endif()
|
endif()
|
||||||
if(TARGET Qt6::Widgets)
|
if(TARGET Qt6::Widgets)
|
||||||
qt_internal_add_example(imagescaling)
|
qt_internal_add_example(imagescaling)
|
||||||
qt_internal_add_example(progressdialog)
|
qt_internal_add_example(primecounter)
|
||||||
qt_internal_add_example(wordcount)
|
qt_internal_add_example(wordcount)
|
||||||
endif()
|
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
|
# SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.16)
|
cmake_minimum_required(VERSION 3.16)
|
||||||
project(progressdialog LANGUAGES CXX)
|
project(primecounter LANGUAGES CXX)
|
||||||
|
|
||||||
if(NOT DEFINED INSTALL_EXAMPLESDIR)
|
if(NOT DEFINED INSTALL_EXAMPLESDIR)
|
||||||
set(INSTALL_EXAMPLESDIR "examples")
|
set(INSTALL_EXAMPLESDIR "examples")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/qtconcurrent/progressdialog")
|
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/qtconcurrent/primecounter")
|
||||||
|
|
||||||
find_package(Qt6 REQUIRED COMPONENTS Concurrent Core Gui Widgets)
|
find_package(Qt6 REQUIRED COMPONENTS Concurrent Core Gui Widgets)
|
||||||
|
|
||||||
qt_standard_project_setup()
|
qt_standard_project_setup()
|
||||||
|
|
||||||
qt_add_executable(progressdialog
|
qt_add_executable(primecounter
|
||||||
main.cpp
|
main.cpp
|
||||||
|
primecounter.ui
|
||||||
|
primecounter.cpp
|
||||||
|
primecounter.h
|
||||||
)
|
)
|
||||||
|
|
||||||
set_target_properties(progressdialog PROPERTIES
|
set_target_properties(primecounter PROPERTIES
|
||||||
WIN32_EXECUTABLE FALSE
|
WIN32_EXECUTABLE TRUE
|
||||||
MACOSX_BUNDLE TRUE
|
MACOSX_BUNDLE TRUE
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(progressdialog PRIVATE
|
target_link_libraries(primecounter PRIVATE
|
||||||
Qt6::Concurrent
|
Qt6::Concurrent
|
||||||
Qt6::Core
|
Qt6::Core
|
||||||
Qt6::Gui
|
Qt6::Gui
|
||||||
Qt6::Widgets
|
Qt6::Widgets
|
||||||
)
|
)
|
||||||
|
|
||||||
install(TARGETS progressdialog
|
install(TARGETS primecounter
|
||||||
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
|
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||||
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
|
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||||
LIBRARY 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
|
TEMPLATE = subdirs
|
||||||
SUBDIRS = imagescaling \
|
SUBDIRS = imagescaling \
|
||||||
progressdialog \
|
primecounter \
|
||||||
wordcount
|
wordcount
|
||||||
|
|
||||||
!qtHaveModule(widgets) {
|
!qtHaveModule(widgets) {
|
||||||
SUBDIRS -= \
|
SUBDIRS -= \
|
||||||
imagescaling \
|
imagescaling \
|
||||||
progressdialog \
|
primecounter \
|
||||||
wordcount
|
wordcount
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user