summaryrefslogtreecommitdiffstats
path: root/examples/qtconcurrent/imagescaling/imagescaling.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'examples/qtconcurrent/imagescaling/imagescaling.cpp')
-rw-r--r--examples/qtconcurrent/imagescaling/imagescaling.cpp150
1 files changed, 60 insertions, 90 deletions
diff --git a/examples/qtconcurrent/imagescaling/imagescaling.cpp b/examples/qtconcurrent/imagescaling/imagescaling.cpp
index 66bb0686c3..f380ae9d90 100644
--- a/examples/qtconcurrent/imagescaling/imagescaling.cpp
+++ b/examples/qtconcurrent/imagescaling/imagescaling.cpp
@@ -1,64 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
#include "imagescaling.h"
#include "downloaddialog.h"
#include <QNetworkReply>
-#include <qmath.h>
-
-#include <functional>
-
-Images::Images(QWidget *parent) : QWidget(parent), downloadDialog(new DownloadDialog())
+Images::Images(QWidget *parent) : QWidget(parent), downloadDialog(new DownloadDialog(this))
{
- setWindowTitle(tr("Image downloading and scaling example"));
resize(800, 600);
addUrlsButton = new QPushButton(tr("Add URLs"));
@@ -87,6 +36,11 @@ Images::Images(QWidget *parent) : QWidget(parent), downloadDialog(new DownloadDi
mainLayout->addStretch();
mainLayout->addWidget(statusBar);
setLayout(mainLayout);
+
+//! [6]
+ connect(&scalingWatcher, &QFutureWatcher<QList<QImage>>::finished,
+ this, &Images::scaleFinished);
+//! [6]
}
Images::~Images()
@@ -99,6 +53,7 @@ void Images::process()
{
// Clean previous state
replies.clear();
+ addUrlsButton->setEnabled(false);
if (downloadDialog->exec() == QDialog::Accepted) {
@@ -114,33 +69,34 @@ void Images::process()
statusBar->showMessage(tr("Downloading..."));
//! [3]
-//! [4]
- downloadFuture.then([this](auto) { cancelButton->setEnabled(false); })
- .then(QtFuture::Launch::Async,
- [this] {
- QMetaObject::invokeMethod(this,
- [this] { updateStatus(tr("Scaling...")); });
- return scaled();
- })
-//! [4]
-//! [5]
- .then(this, [this](const QList<QImage> &scaled) {
- showImages(scaled);
- updateStatus(tr("Finished"));
+ //! [4]
+ downloadFuture
+ .then([this](auto) {
+ cancelButton->setEnabled(false);
+ updateStatus(tr("Scaling..."));
+ //! [16]
+ scalingWatcher.setFuture(QtConcurrent::run(Images::scaled,
+ downloadFuture.results()));
+ //! [16]
+ })
+ //! [4]
+ //! [5]
+ .onCanceled([this] {
+ updateStatus(tr("Download has been canceled."));
})
-//! [5]
-//! [6]
- .onCanceled([this] { updateStatus(tr("Download has been canceled.")); })
.onFailed([this](QNetworkReply::NetworkError error) {
updateStatus(tr("Download finished with error: %1").arg(error));
-
// Abort all pending requests
abortDownload();
})
- .onFailed([this](const std::exception& ex) {
+ .onFailed([this](const std::exception &ex) {
updateStatus(tr(ex.what()));
+ })
+ //! [5]
+ .then([this]() {
+ cancelButton->setEnabled(false);
+ addUrlsButton->setEnabled(true);
});
-//! [6]
}
}
@@ -154,22 +110,37 @@ void Images::cancel()
}
//! [7]
+//! [15]
+void Images::scaleFinished()
+{
+ const OptionalImages result = scalingWatcher.result();
+ if (result.has_value()) {
+ const auto scaled = result.value();
+ showImages(scaled);
+ updateStatus(tr("Finished"));
+ } else {
+ updateStatus(tr("Failed to extract image data."));
+ }
+ addUrlsButton->setEnabled(true);
+}
+//! [15]
+
//! [8]
QFuture<QByteArray> Images::download(const QList<QUrl> &urls)
-//! [8]
{
+//! [8]
//! [9]
QSharedPointer<QPromise<QByteArray>> promise(new QPromise<QByteArray>());
promise->start();
//! [9]
-//! [10]
- for (auto url : urls) {
+ //! [10]
+ for (const auto &url : urls) {
QSharedPointer<QNetworkReply> reply(qnam.get(QNetworkRequest(url)));
replies.push_back(reply);
-//! [10]
+ //! [10]
-//! [11]
+ //! [11]
QtFuture::connect(reply.get(), &QNetworkReply::finished).then([=] {
if (promise->isCanceled()) {
if (!promise->future().isFinished())
@@ -181,25 +152,24 @@ QFuture<QByteArray> Images::download(const QList<QUrl> &urls)
if (!promise->future().isFinished())
throw reply->error();
}
-//! [12]
+ //! [12]
promise->addResult(reply->readAll());
// Report finished on the last download
- if (promise->future().resultCount() == urls.size()) {
+ if (promise->future().resultCount() == urls.size())
promise->finish();
- }
-//! [12]
- }).onFailed([=] (QNetworkReply::NetworkError error) {
+ //! [12]
+ }).onFailed([promise] (QNetworkReply::NetworkError error) {
promise->setException(std::make_exception_ptr(error));
promise->finish();
- }).onFailed([=] {
+ }).onFailed([promise] {
const auto ex = std::make_exception_ptr(
std::runtime_error("Unknown error occurred while downloading."));
promise->setException(ex);
promise->finish();
});
}
-//! [11]
+ //! [11]
//! [13]
return promise->future();
@@ -207,15 +177,14 @@ QFuture<QByteArray> Images::download(const QList<QUrl> &urls)
//! [13]
//! [14]
-QList<QImage> Images::scaled() const
+Images::OptionalImages Images::scaled(const QList<QByteArray> &data)
{
QList<QImage> scaled;
- const auto data = downloadFuture.results();
- for (auto imgData : data) {
+ for (const auto &imgData : data) {
QImage image;
image.loadFromData(imgData);
if (image.isNull())
- throw std::runtime_error("Failed to load image.");
+ return std::nullopt;
scaled.push_back(image.scaled(100, 100, Qt::KeepAspectRatio));
}
@@ -238,6 +207,7 @@ void Images::initLayout(qsizetype count)
QLayoutItem *child;
while ((child = imagesLayout->takeAt(0)) != nullptr) {
child->widget()->setParent(nullptr);
+ delete child->widget();
delete child;
}
labels.clear();