QT简单入门实例7【解决界面阻塞问题】
阅读原文时间:2021年04月23日阅读:1

界面卡死的原因:

1.密集计算

当你想在主线程创建类似 while(1)的这种死循环时,你可能会写下这样的代码:

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
}
MainWindow::~MainWindow()
{
    delete ui;
}
void MainWindow::on_pushButton_clicked()
{
    while(1)
        qDebug()<<"1";
}

当按钮槽函数被执行时,界面会被阻塞,确切的说是界面所在的主线程被占用,无法响应任何事件。

2. 调用阻塞

当你在主线程调用动态库或脚本时,比如你调用了一个python接口,但调用这个接口花费了一些时间。
直到调用过程返回,主线程都无法响应任何事件。即使这个时间很短(比如几十毫秒),也足以使你的界面响应卡顿,严重影响用户体验。

解决方法:

1.最简易的解决办法,但是效果不好

你可以在循环中加入这样一句话,编译器就会让CPU留出一部分时间用以响应事件。

    while(1){
        qApp->processEvents(); //开启事件循环
        qDebug()<<"1";
    }

你也可以这样做:要记得添加头文件 #include < QTime >
以非阻塞的方式延时10ms,本质也是调用了QCoreApplication::processEvents()

void MainWindow::on_pushButton_clicked()
{
    while(1){
        delayMSec(10); //延时10ms
        qDebug()<<"1";
    }
}
void MainWindow::delayMSec(unsigned int msec)
{
    QTime Time_set = QTime::currentTime().addMSecs(msec);
    while( QTime::currentTime() < Time_set )
        QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
}

但是一旦计算变得很密集,或者调用接口变得时间更长,这种方法就显得很无力了。

2.最彻底的解决办法,也是最专业的办法

  1. 当你要执行一个计算密集但不频繁的操作时,明智的办法是采用异步计算来实现。可以借助 QtConcurrent,QFuture,QFutureWatcher 将函数放在子线程进行异步计算。
  2. 当你要执行一个频繁的UI无关操作时,可以使用QThread 来开启一个长期运行的子线程,但是要警惕多线程的冲突与死锁。还有,最好使用 QObject::moveToThread(QThread* thread) 方法,而不是重写QThread 类的虚函数run() 来实现。线程间若采用信号槽进行通信,要注意其连接方式。

这两种方法具体请参照我后面的博文,我会以最简单直接的方式进行说明。

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章