summaryrefslogtreecommitdiffstats
path: root/examples/qtconcurrent/imagescaling/doc/src/qtconcurrent-imagescaling.qdoc
diff options
context:
space:
mode:
Diffstat (limited to 'examples/qtconcurrent/imagescaling/doc/src/qtconcurrent-imagescaling.qdoc')
-rw-r--r--examples/qtconcurrent/imagescaling/doc/src/qtconcurrent-imagescaling.qdoc140
1 files changed, 136 insertions, 4 deletions
diff --git a/examples/qtconcurrent/imagescaling/doc/src/qtconcurrent-imagescaling.qdoc b/examples/qtconcurrent/imagescaling/doc/src/qtconcurrent-imagescaling.qdoc
index 0134f0f8e8..a919b7e2ed 100644
--- a/examples/qtconcurrent/imagescaling/doc/src/qtconcurrent-imagescaling.qdoc
+++ b/examples/qtconcurrent/imagescaling/doc/src/qtconcurrent-imagescaling.qdoc
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the documentation of the Qt Toolkit.
@@ -28,10 +28,142 @@
/*!
\example imagescaling
\title Image Scaling Example
- \brief Demonstrates how to asynchronously scale images.
+ \brief Demonstrates how to asynchronously download and scale images.
\ingroup qtconcurrentexamples
\image imagescaling_example.png
- The QtConcurrent Map example shows how to use the asynchronous
- QtConcurrent API to load and scale a collection of images.
+ This example shows how to use the QFuture and QPromise classes to download a
+ collection of images from the network and scale them, without blocking the UI.
+
+ The application consists of the the following steps:
+
+ \list 1
+ \li Download images form the list of URLs specified by the user.
+ \li Scale the images.
+ \li Show the scaled images in a grid layout.
+ \endlist
+
+ Let's start with the download:
+
+ \snippet imagescaling/imagescaling.cpp 8
+
+ The \c download() method takes a list of URLs and returns a QFuture. The QFuture
+ stores the byte array data received for each downloaded image. To store the data
+ inside the QFuture, we create a QPromise object and report that it has started to
+ indicate the start of the download:
+
+ \snippet imagescaling/imagescaling.cpp 9
+ \dots
+ \snippet imagescaling/imagescaling.cpp 13
+
+ The future associated with the promise is returned to the caller.
+
+ Without going into details yet, let's note that the promise object is wrapped
+ inside a QSharedPointer. This will be explained later.
+
+ We use QNetworkAccessManager to send network requests and download data for each
+ url:
+
+ \snippet imagescaling/imagescaling.cpp 10
+
+ And here starts the interesting part:
+
+ \dots
+ \snippet imagescaling/imagescaling.cpp 11
+ \dots
+
+ Instead of connecting to QNetworkReply's signals using the QObject::connect()
+ method, we use QtFuture::connect(). It works similar to QObject::connect(), but
+ returns a QFuture object, that becomes available as soon as the
+ QNetworkReply::finished() signal is emitted. This allows us to attach continuations
+ and failure handlers, as it is done in the example.
+
+ In the continuation attached via \b{.then()}, we check if the user has requested to
+ cancel the download. If that's the case, we stop processing the request. By calling
+ the \c QPromise::finish() method, we notify the user that processing has been finished.
+ In case the network request has ended with an error, we throw an exception. The
+ exception will be handled in the failure handler attached using the \b{.onFailed()}
+ method. Note that we have two failure handlers: the first one captures the network
+ errors, the second one all other exceptions thrown during the execution. Both handlers
+ save the exception inside the promise object (to be handled by the caller of the
+ \c download() method) and report that the computation has finished. Also note that,
+ for simplicity, in case of an error we interrupt all pending downloads.
+
+ If the request has not been canceled and no error occurred, we read the data from
+ the network reply and add it to the list of results of the promise object:
+
+ \dots
+ \snippet imagescaling/imagescaling.cpp 12
+ \dots
+
+ If the number of results stored inside the promise object is equal to the number
+ of the \c {url}s to be downloaded, there are no more requests to process, so we also
+ report that the promise has finished.
+
+ As mentioned earlier, we've wrapped the promise inside a QSharedPointer.
+ Since the promise object is shared between handlers connected to each network reply,
+ we need to copy and use the promise object in multiple places simultaneously. Hence,
+ a QSharedPointer is used.
+
+ \c download() method is called from the \c QImage::process method. It is invoked
+ when the user presses the \e {"Add URLs"} button:
+
+ \dots
+ \snippet imagescaling/imagescaling.cpp 1
+ \dots
+
+ After clearing the possible leftovers from previous download, we create a dialog
+ so that the user can specify the URLs for the images to download. Based on the
+ specified URL count, we initialize the layout where the images will be shown and
+ start the download. The future returned by the \c download() method is saved, so that
+ the user can cancel the download if needed:
+
+ \snippet imagescaling/imagescaling.cpp 3
+ \dots
+
+ Next, we attach a continuation to handle the scaling step:
+
+ \snippet imagescaling/imagescaling.cpp 4
+ \dots
+
+ Since the scaling may be computationally heavy, and we don't want to block the main
+ thread, we pass the \c QtFuture::Launch::Async option, to launch the scaling step in
+ a new thread.
+
+ The \c scaled() method returns a list of the scaled images to the next step, which
+ takes care of showing images in the layout:
+
+ \dots
+ \snippet imagescaling/imagescaling.cpp 5
+ \dots
+
+ Note that showImages() needs to be invoked from the main thread, so we call it through
+ QMetaObject::invokeMethod().
+
+ Then we add cancellation and failure handlers:
+
+ \dots
+ \snippet imagescaling/imagescaling.cpp 6
+
+ The handler attached via the \c .onCanceled() method will be called if the user has
+ pressed the \e "Cancel" button:
+
+ \dots
+ \snippet imagescaling/imagescaling.cpp 2
+ \dots
+
+ The \c cancel() method simply aborts all the pending requests:
+
+ \snippet imagescaling/imagescaling.cpp 7
+
+ The handlers attached via \c .onFailed() method will be called in case an
+ error occurred during one of the previous steps. For example, if a network error
+ has been saved inside the promise during the download step, it will be propagated to
+ the handler that takes \c QNetworkReply::NetworkError as argument. A failure can
+ happen also during the scaling step:
+
+ \snippet imagescaling/imagescaling.cpp 14
+
+ The rest of the code is straightforward, you can check the example project for
+ more details.
*/