Escalado de Imágenes TaskTree
Demuestra cómo ejecutar iteraciones del bucle For en paralelo para descargar y escalar imágenes de forma asíncrona utilizando TaskTree.
Este ejemplo muestra cómo utilizar las clases Qt TaskTree para descargar una colección de imágenes de la red y escalarlas sin bloquear la interfaz de usuario. Demuestra cómo utilizar el elemento For para ejecutar subtareas en un bucle paralelo sobre elementos de QList, y cómo utilizar el elemento Storage para compartir datos entre tareas.
Este ejemplo proporciona una implementación alternativa para el ejemplo de escalado de imágenes en Qt Concurrent.

Flujo de trabajo de la aplicación
Cuando el usuario pulsa el botón Add URLs, se ejecuta el siguiente método:
DownloadDialog dialog(this); if (dialog.exec() != QDialog::Accepted) return; const QList<QUrl> urls = dialog.getUrls(); initLayout(urls.size());
El método se ejecuta DownloadDialog. Cuando el usuario acepta el diálogo, el método obtiene la lista de URL seleccionadas, borra las imágenes mostradas y prepara una rejilla para nuevas imágenes llamando a initLayout(urls.size()).
Para cada elemento de la lista urls, la aplicación:
- Descarga la imagen para una dirección dada utilizando QNetworkReplyWrapper y almacena los datos recibidos de QByteArray localmente.
- Utiliza QThreadFunction para convertir los datos de QByteArray en QImage y los escala a una miniatura en un subproceso separado.
- Muestra la miniatura resultante en la cuadrícula.
Para iterar sobre la lista urls, la aplicación utiliza un elemento iterator de tipo ListIterator. Los datos de QByteArray recibidos tras la descarga se almacenan en el elemento storage de tipo Storage<QByteArray>, que se utiliza para pasar los datos a la función de escala.
const ListIterator iterator(urls); const Storage<QByteArray> storage;
El recipe que describe el flujo de trabajo tiene este aspecto:
const Group recipe = For (iterator) >> Do { finishAllAndSuccess, parallel, onGroupSetup(onRootSetup), Group { storage, QNetworkReplyWrapperTask(onDownloadSetup, onDownloadDone), QThreadFunctionTask<QImage>(onScaleSetup, onScaleDone) }, onGroupDone(onRootDone) }; taskTreeRunner.start(recipe);
He aquí un resumen de todos los elementos utilizados en la receta:
| Elemento | Propósito |
|---|---|
| For | Bucle de nivel superior que itera sobre una lista de urls. |
| Do | Describe el cuerpo de cada iteración. |
| finishAllAndSuccess | Ordena al árbol de tareas que continúe ejecutándose a pesar de los errores e informe del éxito cuando haya terminado. |
| parallel | Hace que todos los hijos directos del cuerpo de Do se ejecuten en paralelo, incluidas todas las iteraciones del elemento de nivel superior For. Esto significa que todas las iteraciones comenzarán simultáneamente. |
| onGroupSetup(onRootSetup) | Invoca al manejador onRootSetup cuando la primera iteración está a punto de ejecutarse. |
| onGroupDone(onRootDone) | Invoca al manejador onRootDone cuando todas las iteraciones han terminado. |
| Group | Un subgrupo, ejecutado para cada iteración. Por defecto, todos sus hijos se ejecutan en secuencia. |
storage | Indica al árbol de tareas en ejecución que instancie la instancia QByteArray subyacente al entrar en el subgrupo. Esto significa que el árbol de tareas en ejecución instanciará una copia separada de QByteArray para cada iteración. |
| QNetworkReplyWrapperTask | La primera tarea asíncrona que se ejecuta en secuencia para cada iteración. Inicia la descarga de los datos de QByteArray para un Cuando termina, se invoca a |
| QThreadFunctionTask<QImage> | La segunda tarea asíncrona ejecutada en secuencia para cada iteración. Se ejecuta sólo después de la ejecución exitosa de la primera tarea. Ejecuta una función en un hilo separado, pasando los datos almacenados QByteArray de la imagen descargada. Cuando la función está a punto de comenzar, se invoca a Cuando termina, se invoca a |
Actualizar la barra de estado
A continuación se muestra cómo se implementan todos los manejadores:
const auto onRootSetup = [this] { statusBar->showMessage(tr("Downloading and Scaling...")); cancelButton->setEnabled(true); }; const auto onRootDone = [this](DoneWith result) { const QString message = result == DoneWith::Cancel ? tr("Canceled.") : tr("Finished."); statusBar->showMessage(message); cancelButton->setEnabled(false); };
Cuando se inicia la primera iteración, el manejador onRootSetup actualiza el mensaje de la barra de estado y habilita el botón Cancel. Cuando finaliza la última iteración, el controlador onRootDone actualiza el mensaje de la barra de estado y desactiva el botón Cancel.
Descargar y escalar imágenes
Cada iteración se ejecuta en paralelo con otras y consta de dos tareas secuenciales. La primera tarea de cada iteración es QNetworkReplyWrapperTask. A continuación se muestra cómo se implementan sus manejadores de configuración y finalización:
const auto onDownloadSetup = [this, iterator](QNetworkReplyWrapper &task) { task.setNetworkAccessManager(&qnam); task.setRequest(QNetworkRequest(*iterator)); }; const auto onDownloadDone = [this, storage, iterator](const QNetworkReplyWrapper &task, DoneWith result) { const int it = iterator.iteration(); if (result == DoneWith::Success) *storage = task.reply()->readAll(); else if (result == DoneWith::Error) labels[it]->setText(tr("Download\nError.\nCode: %1.").arg(task.reply()->error())); else labels[it]->setText(tr("Canceled.")); };
El gestor onDownloadSetup se ejecuta cuando QNetworkReplyWrapper está a punto de comenzar. Configura el gestor de acceso a la red y la petición de red. El manejador captura el iterator, que da acceso a la dirección actual de la lista urls.
El manejador onDownloadDone se ejecuta cuando QNetworkReplyWrapper termina. Captura storage y iterator. Si la tarea tiene éxito, almacena los datos recibidos de QByteArray en storage. El árbol de tareas crea una instancia de QByteArray distinta para cada iteración. La desreferencia a storage da acceso a la instancia QByteArray para la iteración actual. Si la tarea falla o se cancela, el manejador muestra inmediatamente el mensaje de error de la etiqueta. El índice de la iteración actual es devuelto por iterator.iteration().
La segunda tarea en cada iteración es QThreadFunctionTask<QImage>. Sus handlers de setup y done son los siguientes:
const auto onScaleSetup = [storage](QThreadFunction<QImage> &task) { task.setThreadFunctionData(&scale, *storage); }; const auto onScaleDone = [this, iterator](const QThreadFunction<QImage> &task, DoneWith result) { const int it = iterator.iteration(); if (result == DoneWith::Success) labels[it]->setPixmap(QPixmap::fromImage(task.result())); else if (result == DoneWith::Error) labels[it]->setText(tr("Image\nData\nError.")); else labels[it]->setText(tr("Canceled.")); };
Dentro de onScaleSetup, el manejador programa una llamada a la función scale, pasando los datos QByteArray recibidos de la primera tarea como argumento. Esto se hace desreferenciando el storage capturado. La función scale se ejecuta en un hilo independiente.
El manejador onScaleDone se ejecuta cuando finaliza la función scale. onScaleDone se llama desde el hilo principal. Si el escalado tiene éxito, el manejador asigna la imagen escalada a la etiqueta apropiada. En caso contrario, muestra un mensaje de error.
A continuación se muestra cómo se implementa la función scale:
static void scale(QPromise<QImage> &promise, const QByteArray &data) { const auto image = QImage::fromData(data); if (image.isNull()) promise.future().cancel(); else promise.addResult(image.scaled(100, 100, Qt::KeepAspectRatio)); }
La función toma como argumento un QPromise al tipo de resultado. El promise se utiliza para devolver el resultado final o para emitir un error cancelando el futuro de la promesa.
Ejecución del ejemplo
Para ejecutar el ejemplo desde Qt Creator, abra el modo Welcome y seleccione el ejemplo de Examples. Para más información, ver Qt Creator: Tutorial: Construir y ejecutar.
© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.