Qt简单任务的多线程操作(无需创建类)

在qt中经常会遇到执行一个任务稍微有点耗时,放在主线程中会使界面无响应,但是创建一个类,再把类放到多线程中,又觉得费事,只是想调用一个函数而已,这时你需要用到qt的QtConcurrent,一个非常好用的后台线程执行类函数,下面介绍使用方法。

1.整体用法如下:QtConcurrent::run在后台执行,QMetaObject::invokeMethod回到主线程,这是Qt多线程编程的标准模式;

cpp 复制代码
QtConcurrent::run([=]() {
    // ✅ 这里是在后台线程执行(非UI线程)
    // 可以执行耗时操作,不会阻塞界面
    

    // 执行完成后...
    QMetaObject::invokeMethod(this, [=]() {
        // ✅ 这里回到主线程(UI线程)
        // 可以安全地更新界面
    });
});
  1. QtConcurrent::run - 后台线程,这里能写和不能写的内容如下:
cpp 复制代码
QtConcurrent::run([=]() {
    qDebug() << "当前线程:" << QThread::currentThread();
    // 输出:可能是 QThreadPoolThread (不是主线程)
    
    // 这里可以:
    // - 执行耗时计算
    // - 运行外部程序
    // - 读写大文件
    // - 网络请求
    
    // 这里不能:
    // - 直接更新UI组件 ❌
    // - 直接访问UI对象 ❌
});

其实很好理解,只有主线程能更新界面,这里的 lambda函数已经不是主线程了,所以绝对不能把更新界面的内容写进去。

  1. QMetaObject::invokeMethod - 回到主线程,这里就可以更新界面了,具体写法有两种:

方式1:使用 lambda

cpp 复制代码
QMetaObject::invokeMethod(this, [=]() {
    qDebug() << "回到主线程:" << QThread::currentThread();
    // 输出:main thread (UI线程)
    
    // 这里可以:
    // - 更新文本框 ✅ ui->textEdit->setText()
    // - 修改按钮状态 ✅ ui->button->setEnabled()
    // - 显示对话框 ✅ QMessageBox::information()
});

方式2:调用成员函数

cpp 复制代码
QMetaObject::invokeMethod(this, "updateUI", 
    Qt::QueuedConnection, 
    Q_ARG(QString, result));

//对应的槽函数:
void MainWindow::updateUI(const QString& result) {
    // 这个函数在主线程执行
    ui->outputTextEdit->setText(result);
}

QtConcurrent实现了在一个函数里可以在其他线程和主线程之间来回切换,灵活调用你想执行的代码。

还没看懂怎么用吗?那再附上一个小例子:

cpp 复制代码
void MainWindow::runExternalProgram() {
    // 显示"开始"状态(主线程)
    ui->statusLabel->setText("开始执行...");
    ui->progressBar->setValue(0);
    
    // 启动后台任务
    QtConcurrent::run([this]() {
        // ========== 后台线程开始 ==========
        QProcess process;
        QString appImage = getAppImagePath();
        QString config = getConfigPath();
        
        // 耗时操作:启动外部程序并等待
        process.start(appImage, QStringList() << "librelane" << config);
        process.waitForFinished(30000); // 等待30秒
        
        // 获取结果
        QString output = process.readAllStandardOutput();
        int exitCode = process.exitCode();
        
        // 回到主线程更新UI
        QMetaObject::invokeMethod(this, [this, output, exitCode]() {
            // ========== 回到主线程 ==========
            if (exitCode == 0) {
                ui->statusLabel->setText("执行成功");
                ui->outputTextEdit->setPlainText(output);
                
                // 执行后续操作
                processResults(output);
            } else {
                ui->statusLabel->setText("执行失败");
                QString error = process.readAllStandardError();
                ui->outputTextEdit->setPlainText("错误:" + error);
            }
            
            ui->progressBar->setValue(100);
        });
        // ========== 后台线程结束 ==========
    });
    
    // 这里立即返回,界面不会卡住
    qDebug() << "任务已提交到后台线程";
}
相关推荐
九转成圣6 小时前
Java 性能优化实战:如何将海量扁平数据高效转化为类目字典树?
java·开发语言·json
SmartRadio6 小时前
ESP32-S3 双模式切换实现:兼顾手机_路由器连接与WiFi长距离通信
开发语言·网络·智能手机·esp32·长距离wifi
laowangpython7 小时前
Rust 入门:GitHub 热门内存安全编程语言
开发语言·其他·rust·github
我叫汪枫7 小时前
在后台管理系统中,如何递归和选择保留的思路来过滤菜单
开发语言·javascript·node.js·ecmascript
_.Switch7 小时前
东方财富股票数据JS逆向:secids字段和AES加密实战
开发语言·前端·javascript·网络·爬虫·python·ecmascript
软件技术NINI7 小时前
webkit简介及工作流程
开发语言·前端·javascript·udp·ecmascript·webkit·yarn
Brendan_0017 小时前
JavaScript的Stomp.over
开发语言·javascript·ecmascript
念2347 小时前
f5 shape分析
开发语言·javascript·ecmascript
苍穹之跃7 小时前
某量JS逆向
开发语言·javascript·ecmascript
思茂信息7 小时前
CST软件如何进行参数化扫描?
运维·开发语言·javascript·windows·ecmascript·软件工程·软件需求