Qt子執行緒如何更新UI,完整的程式碼示例,有圖有真相
阿新 • • 發佈:2018-12-09
Qt涉及到大量的資料更新,影象處理,視訊編解碼時,在主執行緒直接進行會讓主執行緒阻塞,程式直接卡死,直達阻塞的部分完成,介面才更新,例如,我們需要在TextBrowser上迴圈顯示資料。
我需要點選【新增新行資料】,然後每隔1秒迴圈顯示資料,之前我是在主執行緒的【新增新行資料】的槽函式直接寫,這樣介面就卡死了,知道迴圈結束,資料才顯示出來,且無法操作介面,這在開發中是不允許的。
我的程式設計環境VS2015 + Qt5.7.0
垃圾程式碼如下:
void QtGuiApplication1::addNew() { for (int i = 0; i < 10; i++) { ui.textBrowser->insertPlainText("11111\n"); } }
所以,需要在子執行緒中進行資料重新整理,Qt的多執行緒和MFC有一定的區別,在MFC中用AfxBeginThread即可建立執行緒,還可以直接操作UI,但是Qt不行,Qt的子執行緒無法直接操作UI,需要用訊號的槽的機制。
例如我的子執行緒標頭檔案 ShowNumber.h 如下:
#pragma once #include <QThread> #include "QtGuiApplication1.h" class ShowNumber : public QThread { Q_OBJECT public: ShowNumber(QtGuiApplication1 *gui); ~ShowNumber(); void run(); signals: void showNum(); public slots: void slotUpdateUi(); public: QtGuiApplication1 *m_gui; //主執行緒物件指標 };
註解:Qt的執行緒類只需要直接派生於QThread,重寫run()方法,呼叫時用用start()方法即可,例如下面的程式碼,在子執行緒ShowNumber的建構函式的形參是 主執行緒度的物件指標,類似於代理模式,然後在槽函式slotUpdataUi中呼叫主執行緒的函式,進行重新整理資料。
實現檔案ShowNumber.cpp
#include "ShowNumber.h" extern int g_run; ShowNumber::ShowNumber(QtGuiApplication1 *gui) { m_gui = gui; connect(this, SIGNAL(showNum()), this, SLOT(slotUpdateUi())); } ShowNumber::~ShowNumber() { } void ShowNumber::run() { //子執行緒無法操作介面,例如顯示資料怎麼搞?? //發訊號給主執行緒 while (g_run) { //發出訊號,此時呼叫槽函式 emit showNum(); msleep(100); } } void ShowNumber::slotUpdateUi() { m_gui->Display(); }
主程式標頭檔案 QtGuiApplication1.h
#pragma once
#include <QtWidgets/QMainWindow>
#include "ui_QtGuiApplication1.h"
class QtGuiApplication1 : public QMainWindow
{
Q_OBJECT
public:
QtGuiApplication1(QWidget *parent = Q_NULLPTR);
void Display();
public slots:
void addNew();
void stopShow();
private:
Ui::QtGuiApplication1Class ui;
};
QtGuiApplication1.cpp
#include "QtGuiApplication1.h"
#include <QThread>
#include "ShowNumber.h"
int g_run = 0;
QtGuiApplication1::QtGuiApplication1(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
connect(ui.pushButton, SIGNAL(clicked()), this, SLOT(addNew()));
connect(ui.btnStop, SIGNAL(clicked()), this, SLOT(stopShow()));
}
void QtGuiApplication1::addNew()
{
g_run = 1; //啟動子執行緒
ShowNumber *p = new ShowNumber(this);
p->start();
}
void QtGuiApplication1::Display()
{
ui.textBrowser->insertPlainText("11111\n");
}
//終止子執行緒,停止重新整理
void QtGuiApplication1::stopShow()
{
g_run = 0;
}
這樣執行之後,點選【新增新行資料】就可以實時重新整理資料了。
程式碼不難,仔細理解。