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

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

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

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

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

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

 二、具体流程及代码片段

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

.h文件

#pragma once
#include<QObject>
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<QThread>
#include<QtWidgets>
#include<QDebug>
#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<QtWidgets/QMainWindow>
#include"ui_qtwidgetsapplication.h"
#include"thTest.h"
#include<QDateTime>
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<QDebug>
#include<QThread>

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 <QtWidgets/QApplication>
#include <QtWidgets/qsplashscreen.h>
#include<QThread>
int main(int argc, char* argv[])
{
	QApplication a(argc, argv);
	QtWidgetsApplication w;
	w.show();
	return a.exec();
}

界面:


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

  • 3
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值