Improve the QtConcurrent ImageScaling example

Provide execution context to QFuture continuations, instead of using
QMetaObject::invokeMethod calls for running in the main thread.

Change-Id: Ica7de19494065d677ffc94224781bfbe292b4f21
Reviewed-by: Leena Miettinen <riitta-leena.miettinen@qt.io>
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
This commit is contained in:
Sona Kurazyan 2020-12-08 17:42:12 +01:00
parent f8f955151a
commit 81ed78c293
2 changed files with 18 additions and 12 deletions

View File

@ -128,23 +128,29 @@
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.
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.
The \c scaled() method returns a list of the scaled images to the next step, which
takes care of showing images in the layout:
Note that \c updateStatus() is called through QMetaObject::invokeMethod(),
because it updates the UI and needs to be invoked from the main thread.
\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().
For the same reason \c showImages() also needs to be invoked from the main thread, so
we pass \c this as a context to \c .then(). By default, \c .then() is launched in the
parent's thread, but if a context object is specified, it is launched in the context
object's thread.
Then we add cancellation and failure handlers:
\dots
\snippet imagescaling/imagescaling.cpp 6
We don't need to specify the context anymore, because \c .onCanceled() and the next
handlers will be launched in their parent's context.
The handler attached via the \c .onCanceled() method will be called if the user has
pressed the \e "Cancel" button:

View File

@ -118,24 +118,24 @@ void Images::process()
downloadFuture.then([this](auto) { cancelButton->setEnabled(false); })
.then(QtFuture::Launch::Async,
[this] {
updateStatus(tr("Scaling..."));
QMetaObject::invokeMethod(this,
[this] { updateStatus(tr("Scaling...")); });
return scaled();
})
//! [4]
//! [5]
.then([this](const QList<QImage> &scaled) {
QMetaObject::invokeMethod(this, [this, scaled] { showImages(scaled); });
.then(this, [this](const QList<QImage> &scaled) {
showImages(scaled);
updateStatus(tr("Finished"));
})
//! [5]
//! [6]
.onCanceled([this] { updateStatus(tr("Download has been canceled.")); })
.onFailed([this](QNetworkReply::NetworkError error) {
const auto msg = QString("Download finished with error: %1").arg(error);
updateStatus(tr(msg.toStdString().c_str()));
updateStatus(tr("Download finished with error: %1").arg(error));
// Abort all pending requests
QMetaObject::invokeMethod(this, &Images::abortDownload);
abortDownload();
})
.onFailed([this](const std::exception& ex) {
updateStatus(tr(ex.what()));
@ -256,7 +256,7 @@ void Images::initLayout(qsizetype count)
void Images::updateStatus(const QString &msg)
{
QMetaObject::invokeMethod(this, [this, msg] { statusBar->showMessage(msg); });
statusBar->showMessage(msg);
}
void Images::abortDownload()