4. QtConcurrent::run异步执行

任务目标

本案例演示如何使用 QtConcurrent::run 将耗时函数放到后台线程执行,并通过 QFutureWatcher 在函数完成时自动获取返回值,避免阻塞主线程(UI线程)。

环境依赖

在项目文件(.pro)中添加:

QT += concurrent widgets

关键完整代码


#include <QApplication>
#include <QPushButton>
#include <QLabel>
#include <QVBoxLayout>
#include <QtConcurrent>
#include <QFutureWatcher>
#include <QThread>

// 后台执行的耗时函数(模拟计算)
int heavyWork(int input) {
    QThread::sleep(2);          // 模拟耗时2秒
    return input * 10;
}

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);

    QWidget window;
    QVBoxLayout layout(&window);
    QLabel statusLabel("点击按钮开始异步计算");
    QPushButton startBtn("开始计算");
    layout.addWidget(&statusLabel);
    layout.addWidget(&startBtn);

    // QFutureWatcher 用于监听异步任务结果
    QFutureWatcher<int> watcher;

    // 任务完成时更新UI
    QObject::connect(&watcher, &QFutureWatcher<int>::finished, [&]() {
        statusLabel.setText(QString("计算完成,结果: %1").arg(watcher.result()));
        startBtn.setEnabled(true);
    });

    QObject::connect(&startBtn, &QPushButton::clicked, [&]() {
        statusLabel.setText("正在后台计算...");
        startBtn.setEnabled(false);
        // 在后台线程运行 heavyWork(5)
        QFuture<int> future = QtConcurrent::run(heavyWork, 5);
        watcher.setFuture(future);   // 关联future以监听完成
    });

    window.show();
    return app.exec();
}

运行与验证

运行方式:直接编译运行上述代码。点击“开始计算”按钮后,界面标签立即变为“正在后台计算...”,此时窗口仍可正常拖动、响应(主线程未被阻塞)。约2秒后标签自动更新为“计算完成,结果: 50”。

验证要点:

  • 点击按钮后,若窗口在计算期间仍能正常移动或响应其他操作,说明 heavyWork 确实在后台线程执行,主线程未被阻塞。
  • 最终标签显示结果 50(即 5×10),证明 QFutureWatcher 成功获取了后台线程的返回值。
  • 计算期间按钮处于禁用状态,完成后恢复可用,说明 finished 信号被正确触发。

判定标准:若界面在2秒等待期间无卡顿,且最终显示“结果: 50”,则案例实现正确。