QT簡單入門實例7【解決界面阻塞問題】

界面卡死的原因:

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() 來實現。線程間若採用信號槽進行通信,要注意其連接方式。

這兩種方法具體請參照我後面的博文,我會以最簡單直接的方式進行說明。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章