Qt 耗时任务界面阻塞

背景:主界面免不了进行一些耗时操作,如果界面和是数据处理本身就处于同一个线程,那么使用QCoreApplication::processEvents()是无效的。如果不需要返回值,那么扔进线程池运行就好,使用QObject::moveToThread()。但是需要返回值的时候就会有问题。


解决办法:使用QEventLoop和QtConcurrent:run()。

auto runFunc = [&](){
   //任意耗时操作,我这里是带返回值的静态函数。
    return test();
};
//先创建一个事件循环
QEventLoop loop;
//再创建一个线程执行状态看护者。上面使用的静态函数返回值是int。
QFutureWatcher<int> watcher; 
//连接线程完成和事件循环,当线程操作完成时,退出事件循环。
connect(&watcher,&QFutureWatcher<QPixmap>::finished,&loop,&QEventLoop::quit);
//运行线程,将线程状态给看护者
watcher.setFuture( QtConcurrent::run( runFunc ) );
//函数到此阻塞,进入事件循环,等待回调结果
loop.exec();
//当退出事件循环后,会继续执行以下

//拿到静态函数的执行结果
auto result = watcher.future().result();
//利用结果刷新显示
ui->lbl->setNum(result);

### Qt 中处理耗时任务以防止 UI 阻塞的方法 在 Qt 应用程序开发中,当主线程(即 GUI 线程)执行耗时任务时,可能会导致界面卡顿甚至无响应的情况。为了避免这种情况的发生,可以采用多种方式来实现异步操作并保持线程安全性。 #### 使用 `QCoreApplication::processEvents()` 一种简单的方式是在耗时代码段中调用 `QCoreApplication::processEvents()` 来手动触发事件循环,从而允许窗口系统继续更新界面[^1]。然而需要注意的是,这种方法仅适用于某些特定场景下的短时间阻塞情况,并不推荐用于长期运行的任务,因为这仍然会占用主线程资源。 ```cpp void longRunningTask() { for (int i = 0; i < 100; ++i) { // 执行部分工作... QCoreApplication::processEvents(); // 更新UI if (someCondition()) break; } } ``` #### 利用线程池 (`QThreadPool`) 和 `QtConcurrent` 进行并发编程 对于那些无需复杂交互逻辑的独立型耗时任务来说,可以直接利用 Qt 提供的高级接口——`QtConcurrent` 或者直接管理 `QRunnable` 对象放入全局默认线程池当中去完成这些后台作业[^2]: ```cpp #include <QtConcurrent/QtConcurrentRun> // 定义一个普通的C++函数作为要执行的工作单元 QString doWork(int param){ QString result="Result from thread"; return result; } // 启动该任务并将结果连接至某个槽接收最终成果 auto future = QtConcurrent::run(doWork, someParameter); connect(&watcher, &QFutureWatcher<QString>::finished, this,[&future,this]()mutable{ ui->label->setText(future.result()); }); ``` #### 继承自 `QThread` 的子类模式 另一种常见做法就是创建一个新的继承于标准库中的基础类 `QThread` 的派生类型实例化对象之后再启动它;与此同时还可以定义额外信号量以便通知主进程当前状态变化信息等等[^3]^[]^: ```cpp class Worker : public QObject { Q_OBJECT public slots: void process(){ while(true){ qDebug()<<"Processing..."<<QThread::currentThreadId(); emit progressChanged(value); if(stopFlag)break; QThread::sleep(1); } emit finished(); } signals: void progressChanged(int value); void finished(); private: bool stopFlag=false; }; Worker *worker=new Worker(this); QThread* workerThread=new QThread(this); worker->moveToThread(workerThread); connect(workerThread,&QThread::started,worker,&Worker::process); connect(worker,&Worker::progressChanged,this,&MainWindow::updateProgress); connect(worker,&Worker::finished,[=](){workerThread->quit();}); workerThread->start(); ``` 另外还有一种更灵活的做法是单独构建一个完全基于消息驱动架构设计的新组件模型出来专门负责协调多个不同类型的工作者实体之间的通信协作关系等问题解决方案[^4]. ### 总结 以上介绍了几种常见的解决办法,在实际项目应用过程中可以根据具体情况选择最适合自己的那套方案实施部署即可达到预期效果.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雲烟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值