Qt执行耗时操作导致界面卡顿的三种解决办法

在Qt界面程序开发中,当主线程执行耗时操作如数据库查询时,会导致界面卡顿。为避免这种情况,可以使用Qt::QueuedConnection连接信号槽或QtConcurrent::run将任务放入新线程执行,实现异步处理。此外,还可以自定义QThread子类进行线程操作,确保界面流畅。这些方法能提升程序的交互体验。
摘要由CSDN通过智能技术生成

1.问题描述

Qt界面程序开发中,会遇到执行耗时操作时,导致界面卡顿。原因是界面主线程是单线程,如果在UI主线程中执行耗时操作,例如点击按钮,响应函数去数据库查询数据,数据量比较大时,查询需要几秒钟甚至几十秒的时间,如果UI主线程一直等待响应函数返回,阻塞在响应函数内部,就无法响应界面的其他消息或者事件,界面就会卡死,无响应;

2.解决方法

(1)用Qt::QueuedConnection去连接信号槽

Qt::QueuedConnection是用队列的形式执行操作,点击pushButtonStart按钮之后,会立刻返回,不用等到startSmartApart();执行完成再返回;startSmartApart();5秒内执行完,可以考虑这种方法,超过5秒,界面也会卡顿;

connect(ui.pushButtonStart, &QPushButton::clicked, this, [=]() {
		//QtConcurrent::run(this, &test::startSmartApart);
		startSmartApart();
	},Qt::QueuedConnection);

(2)用QtConcurrent::run将类函数放入线程中执行;

(1)QtConcurrent::run会创建一个新的线程,将类函数放入新的线程中执行;也可以返回返回值;

connect(ui.pushButtonStart, &QPushButton::clicked, this, [=]() {
        QtConcurrent::run(this, &test::startSmartApart);
        //startSmartApart();
    },Qt::QueuedConnection);

(2)可以给执行的类函数startSmartApartCount(int count)传入多个参数,最多5个参数;

connect(ui.pushButtonStart, &QPushButton::clicked, this, [=]() {
        //QtConcurrent::run(this, &test::startSmartApart);
        int retval = -1;
        QtConcurrent::run(this, &test::startSmartApartCount,100);
        //startSmartApart();
    },Qt::QueuedConnection);

(3)同步方法获取函数的返回值,但是 future.waitForFinished();会阻塞主线程等待结果返回,导致界面卡死;

connect(ui.pushButtonStart, &QPushButton::clicked, this, [=]() { 
        int retval = -1;
        QFuture<int> future = QtConcurrent::run(this, &test::startSmartApartCount, 10);
        future.waitForFinished();//阻塞等待结果返回
        qDebug() << future.result();
    },Qt::QueuedConnection);


(4)异步方法获取函数返回值,使用QFutureWatcher信号槽监视返回结果,不阻塞主线程,界面很流畅

//类的成员变量

QFuture<int> future;

QFutureWatcher<int>* watcher;

watcher = new QFutureWatcher<int>();
    connect(ui.pushButtonStart, &QPushButton::clicked, this, [=]() {
         future = QtConcurrent::run(this, &test::startSmartApartCount, 2);
        
        QObject::connect(watcher, &QFutureWatcher<int>::finished,this, [&]() {
            qDebug() << future.result();
        });
        watcher->setFuture(future);
    },Qt::QueuedConnection);

(3)用QThread执行耗时操作

创建线程类

头文件

#include <QThread>
class SmartApartPlayThread : public QThread
{
    Q_OBJECT

public:
    SmartApartPlayThread();
    ~SmartApartPlayThread();
    int StartSmartApartPlay(void* pmulti,int index);
    void run();
signals:
    void signalStartApartPlay(int index);

private:
    void* m_pmulti=nullptr;
    int m_index=0;
};

源文件

#include "SmartApartPlayThread.h"
#include <windows.h>
SmartApartPlayThread::SmartApartPlayThread()
{

}

SmartApartPlayThread::~SmartApartPlayThread()
{

}

int SmartApartPlayThread::StartSmartApartPlay(void* pmulti, int index)
{
    m_pmulti = pmulti;
    m_index = index;
    if (m_pmulti!=nullptr)
    {
        start();
    }
    return 0;
}



void SmartApartPlayThread::run()
{
    
    while (1)
    {
        Sleep(10000);
    }
}

使用线程类

//按钮响应函数中启动线程执行耗时操作

connect(ui.pushButtonStart, &QPushButton::clicked, this, [=]() {
        m_SmartApartPlayThread.StartSmartApartPlay(this,10);
    },Qt::QueuedConnection);
    

3.总结

要实现好的用户体验,实现流程的界面操作程序,就不能老是卡,比较好的方式就是采用异步操作、多线程等方法来实现异步,并发;这样才会有好的交互体验;QtConcurrent::run和线程其实原理上都是多线程并发方式,只是QtConcurrent::run封装了线程的操作;可以执行类函数,更方便一些;

QT界面卡顿的解决方法有以下几种: 1. 优化代码:检查代码是否存在耗时操作,例如循环遍历大量数据或者频繁地进行IO操作。如果有,可以考虑对代码进行优化,减少不必要的计算和IO。 2. 减少界面刷新次数:界面卡顿往往是由于频繁地进行界面刷新引起的,可以通过减少刷新频率来提高界面的响应速度。可以通过使用Qt提供的定时器来控制界面刷新的频率。 3. 多线程处理耗时操作:将耗时操作放在独立的线程中进行处理,避免阻塞主线程的执行。可以使用Qt提供的QThread类或者QtConcurrent库来实现多线程操作。 4. 异步操作:对于可能会阻塞界面操作,可以通过使用信号与槽机制或者Qt提供的异步任务类(如QFuture、QPromise)来实现异步处理,将阻塞操作移出主线程。 5. 减少界面元素的数量和复杂度:复杂的界面元素(如大量的控件、复杂的布局等)会增加界面渲染的负担,可以考虑简化界面,减少不必要的控件和布局的复杂度。 6. 使用硬件加速:如果支持,可以利用硬件加速来提高界面的绘制速度。可以通过使用OpenGL来进行界面的绘制,或者使用Qt提供的QGraphicsView类来实现硬件加速。 总结来说,解决QT界面卡顿的关键是优化代码、减少界面刷新次数、合理使用多线程和异步操作、简化界面元素,并且利用硬件加速来提高界面的响应速度。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值