1. 程式人生 > >Qt子執行緒如何更新UI,完整的程式碼示例,有圖有真相

Qt子執行緒如何更新UI,完整的程式碼示例,有圖有真相

      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;
}

這樣執行之後,點選【新增新行資料】就可以實時重新整理資料了。

程式碼不難,仔細理解。