태스크트리 이미지 크기 조정
태스크트리를 사용하여 비동기적으로 이미지를 다운로드하고 크기를 조정하기 위해 병렬로 For 루프 반복을 실행하는 방법을 보여줍니다.
이 예제는 Qt TaskTree 클래스를 사용하여 네트워크에서 이미지 컬렉션을 다운로드하고 UI를 차단하지 않고 스케일링하는 방법을 보여줍니다. For 요소를 사용하여 QList 항목에 대한 병렬 루프에서 하위 작업을 실행하는 방법과 Storage 요소를 사용하여 작업 간에 데이터를 공유하는 방법을 보여줍니다.
이 예제는 이미지 크기 조정 예제의 대체 구현을 제공합니다. Qt Concurrent.

애플리케이션 워크플로
사용자가 Add URLs 버튼을 누르면 다음 메서드가 실행됩니다:
DownloadDialog dialog(this); if (dialog.exec() != QDialog::Accepted) return; const QList<QUrl> urls = dialog.getUrls(); initLayout(urls.size());
메서드가 실행됩니다 DownloadDialog. 사용자가 대화 상자를 수락하면 메서드는 선택한 URL 목록을 가져오고, 표시된 이미지를 지우고, initLayout(urls.size()) 을 호출하여 새 이미지에 대한 그리드를 준비합니다.
urls 목록의 각 항목에 대해 앱:
- QNetworkReplyWrapper 을 사용하여 지정된 주소의 이미지를 다운로드하고 수신된 QByteArray 데이터를 로컬에 저장합니다.
- QThreadFunction 을 사용하여 QByteArray 데이터를 QImage 로 변환하고 별도의 스레드에서 썸네일로 크기를 조정합니다.
- 결과 썸네일을 그리드에 표시합니다.
urls 목록을 반복하기 위해 앱은 ListIterator 유형의 iterator 요소를 사용합니다. 다운로드 후 받은 QByteArray 데이터는 Storage<QByteArray> 타입의 storage 요소에 저장되며, 이 요소는 데이터를 스케일 함수에 전달하는 데 사용됩니다.
const ListIterator iterator(urls); const Storage<QByteArray> storage;
워크플로우를 설명하는 recipe 은 다음과 같습니다:
const Group recipe = For (iterator) >> Do { finishAllAndSuccess, parallel, onGroupSetup(onRootSetup), Group { storage, QNetworkReplyWrapperTask(onDownloadSetup, onDownloadDone), QThreadFunctionTask<QImage>(onScaleSetup, onScaleDone) }, onGroupDone(onRootDone) }; taskTreeRunner.start(recipe);
다음은 레시피에 사용된 모든 요소의 요약입니다:
| 요소 | 목적 |
|---|---|
| For | urls 의 목록을 반복하는 최상위 루프입니다. |
| Do | 각 반복의 본문을 설명합니다. |
| finishAllAndSuccess | 작업 트리가 오류에도 불구하고 계속 실행되고 완료되면 성공을 보고하도록 지시합니다. |
| parallel | 최상위 수준 For 요소의 모든 반복을 포함하여 Do 본문의 모든 직접 자식이 병렬로 실행되도록 합니다. 즉, 모든 반복이 동시에 시작됩니다. |
| onGroupSetup(onRootSetup) | 첫 번째 반복이 실행될 때 onRootSetup 핸들러를 호출합니다. |
| onGroupDone(onRootDone) | 모든 반복이 완료되면 onRootDone 핸들러를 호출합니다. |
| Group | 각 반복마다 실행되는 하위 그룹입니다. 기본적으로 모든 자식이 순서대로 실행됩니다. |
storage | 실행 중인 작업 트리가 하위 그룹에 들어갈 때 기본 QByteArray 인스턴스를 인스턴스화하도록 지시합니다. 즉, 실행 중인 작업 트리가 각 반복에 대해 별도의 QByteArray 복사본을 인스턴스화합니다. |
| QNetworkReplyWrapperTask | 각 반복에 대해 순차적으로 실행되는 첫 번째 비동기 작업입니다. 주어진 다운로드가 완료되면 |
| QThreadFunctionTask<QImage> | 각 반복마다 순차적으로 실행되는 두 번째 비동기 작업입니다. 첫 번째 태스크가 성공적으로 실행된 후에만 실행됩니다. 별도의 스레드에서 함수를 실행하여 다운로드한 이미지의 저장된 QByteArray 데이터를 전달합니다. 함수가 시작되면 완료되면 |
상태 표시줄 업데이트
다음은 모든 핸들러가 어떻게 구현되는지 보여줍니다:
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); };
첫 번째 반복이 시작되면 onRootSetup 핸들러가 상태 표시줄 메시지를 업데이트하고 Cancel 버튼을 활성화합니다. 마지막 반복이 완료되면 onRootDone 핸들러가 상태 표시줄 메시지를 업데이트하고 Cancel 버튼을 비활성화합니다.
이미지 다운로드 및 크기 조정
각 반복은 다른 반복과 병렬로 실행되며 두 개의 순차적 작업으로 구성됩니다. 각 반복의 첫 번째 작업은 QNetworkReplyWrapperTask 입니다. 설정 및 완료 핸들러가 구현되는 방식은 다음과 같습니다:
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.")); };
onDownloadSetup 핸들러는 QNetworkReplyWrapper 이 시작될 때 실행됩니다. 이 핸들러는 네트워크 액세스 관리자와 네트워크 요청을 설정합니다. 이 핸들러는 iterator 를 캡처하여 urls 목록에서 현재 주소에 대한 액세스를 제공합니다.
onDownloadDone 핸들러는 QNetworkReplyWrapper 이 완료되면 실행됩니다. storage 및 iterator 을 캡처합니다. 작업이 성공하면 수신된 QByteArray 데이터를 storage 에 저장합니다. 작업 트리는 각 반복에 대해 별도의 QByteArray 인스턴스를 만듭니다. storage 을 역참조하면 현재 반복에 대한 QByteArray 인스턴스에 액세스할 수 있습니다. 작업이 실패하거나 취소되면 핸들러는 라벨에 대한 오류 메시지를 즉시 표시합니다. 현재 반복의 인덱스는 iterator.iteration() 에서 반환됩니다.
각 반복의 두 번째 작업은 QThreadFunctionTask<QImage>입니다. 설정 및 완료된 핸들러는 다음과 같습니다:
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.")); };
onScaleSetup 내에서 핸들러는 scale 함수에 대한 호출을 예약하여 첫 번째 작업에서 받은 QByteArray 데이터를 인수로 전달합니다. 이는 캡처된 storage 을 역참조하여 수행됩니다. scale 함수는 별도의 스레드에서 실행됩니다.
onScaleDone 핸들러는 scale 함수가 완료되면 실행됩니다. onScaleDone 는 메인 스레드에서 호출됩니다. 크기 조정에 성공하면 핸들러는 크기 조정된 이미지를 적절한 레이블에 할당합니다. 그렇지 않으면 핸들러는 오류 메시지를 표시합니다.
다음은 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)); }
이 함수는 결과 유형에 QPromise 을 인자로 받습니다. promise 은 최종 결과를 반환하거나 향후 약속을 취소하여 오류를 발생시키는 데 사용됩니다.
예제 실행하기
에서 예제를 실행하려면 Qt Creator에서 예제를 실행하려면 Welcome 모드를 열고 Examples 에서 예제를 선택합니다. 자세한 내용은 Qt Creator: 튜토리얼을 참조하세요 : 빌드 및 실행을 참조하세요.
© 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.