步骤:
1、创建一个自定义Worker类,继承自QObject
2、主线程中创建QThread的对象,Worker类的对象
3、Worker类的对象调用moveToThread函数移动到QThread的对象中
4、主线程自定义一个信号,并使用信号槽连接到worker类对象的任务函数
5、启动线程
6、主线程发射自定义的信号,触发worker类对象的任务函数,这个函数就会在子线程中执行
7、找一个合适的时机或位置完成线程的退出和清理
如下面的例子
点击按钮,ui发射自定义信号,触发Worker的工作函数(工作在子线程中),然后Worker发射信号,主线程更新Label的值
cpp
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include<QThread>
#include<QLabel>
#include<QPushButton>
class Worker:public QObject
{
Q_OBJECT
public:
Worker()=default;
~Worker()=default;
//工作函数,在这个函数中编写业务逻辑
void doWork()
{
//打印下线程id,看和主线程的线程id是否一样
qDebug()<<"工作函数所在线程:"<<QThread::currentThreadId();
int num=0;
while(!stop)
{
//num循环自增,然后发射改变的信号
emit changeString(QString::number(num++));
QThread::msleep(500);
}
}
//终止循环,结束工作函数
void Stop()
{
stop=true;
}
signals:
void changeString(QString text);
private:
bool stop=false;
};
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr): QWidget(parent)
{
qDebug()<<"UI界面所在线程:"<<QThread::currentThreadId();
resize(400,300);
QLabel* info=new QLabel("我是Label",this);
QFont font;
font.setPixelSize(18);
font.setBold(true);
info->setFont(font);
info->setGeometry(10,20,400,100);
QPushButton* btn=new QPushButton("更新Label",this);
btn->setGeometry(10,140,100,30);
//创建辅助线程,
QThread* th=new QThread(this);
//创建任务类,不能指定父指针为this,否则还是会在当前线程
Worker* worker=new Worker;
//移动到线程
worker->moveToThread(th);
//绑定worker发射的信号,来更新ui界面的label
connect(worker,&Worker::changeString,this,[=](QString text){
info->setText("当前num的值:"+text);
});
//绑定自定义的triggerWork信号,来触发worker的工作函数,工作函数就会在子线程中执行
connect(this,&Widget::triggerWork,worker,&Worker::doWork);
//绑定窗口的destroyed信号,窗口关闭时结束掉线程
connect(this,&Widget::destroyed,this,[=](){
worker->Stop();//终止工作函数
th->exit();//线程退出事件循环
th->wait();//等待线程退出
qDebug()<<"线程退出了";
});
//点击按钮,发射triggerWork信号,通过信号来触发前面绑定的工作函数
//(只能通过信号槽,用信号来触发工作函数,才会子线程中执行)
connect(btn,&QPushButton::clicked,this,&Widget::triggerWork);
//手动启动线程
th->start();
}
~Widget()=default;
signals:
//自定义一个信号
void triggerWork();
};
#endif // WIDGET_H