QT中子线程(自定义线程)访问UI线程中的控件的方法

QT中子线程(自定义线程)访问UI线程中的控件的方法,第1张

本人也是刚学习Qt的小白,也算是做个记录吧,这个例子是用VS2019搭建的Qt环境来实现的,主要是获取当前时间并打印到QTextEdit控件里面。



一、本人所知的Qt中线程的创建方式

1.继承QThread类,然后重新实现该类的run()方法。


2.自定义类通过继承QObject后传入到QThread类中来实现。


在4.8以前都是使用第一种方式,在4.8以后官方推荐第二种方式较多,二者区别其实并不大只是第二种方式更灵活,在这里主要是说说第二种方式。


 

二、具体流程及代码片段

1.创建继承自QObject的自定义类

.h文件

#pragma once
#include
class thTest : public QObject
{
	Q_OBJECT

public:
	explicit thTest(QObject* parent = nullptr);
	void closeThread();

signals:
	void sendString(QString);//声明信号

public slots:
	void startThreadSlot();//线程具体执行的函数

private:
	volatile bool thisAlive;
};

.cpp文件

#include"qtwidgetsapplication.h"
#include
#include
#include
#include"thTest.h"	
thTest::thTest(QObject* parent) :QObject(parent)
{
	thisAlive = false;
}

void thTest::closeThread()
{
	thisAlive = true;
}

void thTest::startThreadSlot()
{
	if (thisAlive)
	{
		return;
	}
	while (thisAlive == false)
	{
		QDateTime current_date_time = QDateTime::currentDateTime();
		QString current_date = current_date_time.toString("yyyy.MM.dd hh:mm:ss.zzz ddd");
		qDebug() << tr(current_date.toUtf8());
		emit sendString(current_date);//发射打印文本的信号,将时间传递给主类中的打印槽函数
		Sleep(1000);
		//QThread::sleep(500);
	}
}

2.在主窗体类种的声明和实现部分

主窗体.h文件

#pragma once
#include
#include"ui_qtwidgetsapplication.h"
#include"thTest.h"
#include
class QtWidgetsApplication : public  QMainWindow
{
	Q_OBJECT


public:
	QtWidgetsApplication(QWidget* parent = Q_NULLPTR);

private:
	QThread* thread;
	thTest* thClass;
public:
	Ui::QtWidgetsApplicationClass ui;

public slots:
	void openThreadSlot();
	void closeThreadSlot();
	void finishedThreadSlot();

	void apMsg(QString msg);
};

主窗体.cpp文件

#include"qtwidgetsapplication.h"
#include"thTest.h"
#include
#include

QtWidgetsApplication::QtWidgetsApplication(QWidget* parent)
	: QMainWindow(parent)
{
	thClass = new thTest();

#pragma region 线程按钮绑定信号
	connect(ui.pb_thStart, SIGNAL(clicked(bool)), this, SLOT(openThreadSlot()));/*将ui中按钮控件的点击事件和槽函数绑定在一起*/
	connect(ui.pb_thStop, SIGNAL(clicked(bool)), this, SLOT(closeThreadSlot()));
	connect(thClass, SIGNAL(sendString(QString)), this, SLOT(apMsg(QString)));/*创建槽将子类中的信号与主类中的槽函数连接,不支持跨线程访问主线程(UI线程中的控件),会报异常*/
#pragma endregion

}


void QtWidgetsApplication::apMsg(QString msg)
{
	ui.textEdit->append(msg);//具体执行往QTextEdit里面追加文本
}

void QtWidgetsApplication::openThreadSlot()
{
	qDebug() << trUtf8("Thread Start");
	thread = new QThread();
	thClass->moveToThread(thread);//将继承Object的类传入线程
	connect(thread, SIGNAL(finished()), thClass, SLOT(deleteLater()));//终止线程时要调用deleteLater槽函数
	connect(thread, SIGNAL(started()), thClass, SLOT(startThreadSlot()));  //开启线程槽函数
	connect(thread, SIGNAL(finished()), this, SLOT(finishedThreadSlot()));//线程结束时调用的槽函数
	thread->start();//启动线程
}

void QtWidgetsApplication::closeThreadSlot()
{
	qDebug() << tr("Thread Close");
	if (thread->isRunning())
	{
		thClass->closeThread();//调用自定义类的函数
		thread->quit();
		thread->wait();
		delete thread;
		thread = NULL;
	}
}

void QtWidgetsApplication::finishedThreadSlot()
{
	/*用于线程执行完后,执行这个槽函数里面的代码*/
	qDebug() << tr("Thread Finished");
}

main.cpp文件

#include "qtwidgetsapplication.h"
#include 
#include 
#include
int main(int argc, char* argv[])
{
	QApplication a(argc, argv);
	QtWidgetsApplication w;
	w.show();
	return a.exec();
}

界面:


最后总结:Qt中要从子类访问UI线程中的控件不能通过在子类中实例化对象的方式来进行传值或改变控件等 *** 作,需要通过信号与槽的方式来进行 *** 作,在子类中声明信号,执行线程方法时通过emit来将值或参数传递到主类中的槽函数里面,然后执行这个槽函数,在这个槽函数中来 *** 作控件就可以了。


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/634352.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-16
下一篇 2022-04-16

发表评论

登录后才能评论

评论列表(0条)

保存