第一種方式創(chuàng)建線程工作,繼承QThread,實(shí)現(xiàn)run純虛函數(shù)
1、需要?jiǎng)?chuàng)建一個(gè)繼承QThread的類
2、在類里面實(shí)現(xiàn)run() 純虛函數(shù)
3、實(shí)例化這個(gè)類,調(diào)用父類函數(shù)start(),回調(diào)函數(shù)run()開始執(zhí)行。
4、還可以在這個(gè)類寫一個(gè)信號(hào),信號(hào)不需要實(shí)現(xiàn),信號(hào)也可以帶參數(shù),如果帶參數(shù),需要槽函數(shù)匹配一樣類型參數(shù)接收,這個(gè)不需要賦值,槽函數(shù)參數(shù)自動(dòng)接收。


通過繪制一個(gè)lcd計(jì)數(shù)器,和一個(gè)按鈕,點(diǎn)擊按鈕實(shí)現(xiàn),通過計(jì)時(shí)器每隔500ms觸發(fā)一次timeout信號(hào),在構(gòu)造函數(shù),使用timeout信號(hào)和計(jì)數(shù)器加一綁定一起,每隔500ms,計(jì)數(shù)器就加一,但是如果,timer啟動(dòng)之后有一個(gè)耗時(shí)的工作,那么只能等耗時(shí)的工作完成之后,才會(huì)觸發(fā)timeout信號(hào),導(dǎo)致計(jì)時(shí)器不能同時(shí)工作,所以需要一個(gè)開啟一個(gè)線程,把耗時(shí)工作,放入線程里面。這樣界面的lcd就可以正常啟動(dòng),界面也不會(huì)卡死。
二話不說上代碼
自定義線程頭文件
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QThread>
class myThread : public QThread
{
Q_OBJECT
public:
explicit myThread(QThread *parent = nullptr);
private:
protected:
//繼承QThread run 純虛函數(shù) 純虛函數(shù)一定要寫實(shí)現(xiàn)
//線程內(nèi)容在run函數(shù)里面寫
//自定義線程,回調(diào)函數(shù),當(dāng)自定義線程 myThread.start(),會(huì)進(jìn)入到這里
void run() override;
signals:
//信號(hào),可以寫一個(gè)信號(hào),當(dāng)自定義線程里面內(nèi)容實(shí)現(xiàn)完成,發(fā)生信號(hào)通知線程內(nèi)容已完成。
void done();
};
#endif // MYTHREAD_H
自定義線程.cpp文件
#include "mythread.h"
myThread::myThread(QThread *parent) : QThread(parent)
{
}
void myThread::run()
{
//耗時(shí)工作
//等耗時(shí)工作完成,emit signals ,通知外部,耗時(shí)工作已完成
sleep(5);
emit done();
}
Widget 頭文件
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include<QTimer>
#include<QThread>
#include"mythread.h"
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private slots:
void on_pushButton_clicked();
private:
Ui::Widget *ui;
QTimer *timer;
myThread *m_T;
};
#endif // WIDGET_H
Widget .cpp文件
#include "widget.h"
#include "ui_widget.h"
#include<QElapsedTimer>
#include<QtDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//實(shí)例化計(jì)時(shí)器
timer = new QTimer();
//實(shí)例化線程
m_T= new myThread();
connect(timer,&QTimer::timeout,this,[=](){
static int num =0;
ui->lcdNumber->display(num++);
});
connect(m_T,&myThread::done,this,[=](){
qDebug()<<"線程工作完成";
});
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_clicked()
{
//判斷計(jì)時(shí)器是否是處于活動(dòng)
//以免計(jì)時(shí)器重復(fù)運(yùn)行。
if(true==timer->isActive())
{
return;
}
timer->start(500);
//QT 計(jì)時(shí)函數(shù) QElapsedTimer
//time.start() 開始計(jì)時(shí)
//time.elapsed() 計(jì)時(shí)結(jié)果
// QElapsedTimer time;
// time.start();
// QThread::sleep(3);
// qDebug()<<time.elapsed();
//線程開始,默認(rèn)線程優(yōu)先級(jí),參數(shù)(線程優(yōu)先級(jí))
//通過debug可以得到線程運(yùn)行,通過得到時(shí)間函數(shù),得不出線程工作時(shí)間。
QElapsedTimer time;
time.start();
m_T->start();
qDebug()<<time.elapsed();
}
第二種創(chuàng)建線程工作,調(diào)用工作類(繼承QObject)對(duì)象的moveToThread方法
1、先創(chuàng)建工作類,在工作類里面寫一個(gè)槽函數(shù),一個(gè)信號(hào)(主要是線程執(zhí)行槽函數(shù)通知外部)
#ifndef WORK_H
#define WORK_H
#include <QObject>
#include<QDebug>
class work : public QObject
{
Q_OBJECT
public:
explicit work(QObject *parent = nullptr);
public slots:
//線程工作內(nèi)容
void dowork(int parameter);
signals:
//線程完成工作內(nèi)容發(fā)送的信號(hào)
void resultReady(const int result);
};
#endif // WORK_H
#include "work.h"
work::work(QObject *parent)
: QObject{parent}
{
}
void work::dowork(int parameter)
{
//耗時(shí)工作
qDebug()<<"work start";
for(int i =0;i<1000;++i)
{
++parameter;
}
//耗時(shí)工作完成發(fā)出完成信號(hào)
emit resultReady(parameter);
}
2、創(chuàng)建一個(gè)觸發(fā)或者說是連接線程和工作類的類,在類里面聲明一個(gè)QThred的全局變量。實(shí)例化一個(gè)工作類對(duì)象,調(diào)用這個(gè)對(duì)象的moveToThread類,傳入QThread變量。
#ifndef CONTROLLER_H
#define CONTROLLER_H
#include <QObject>
#include<QThread>
#include<QDebug>
#include"work.h"
class Controller : public QObject
{
Q_OBJECT
QThread workerThread;
public:
explicit Controller(QObject *parent = nullptr);
~Controller()override;
public slots:
//處理線程執(zhí)行的結(jié)果
static void handleResults(int result);
signals:
//發(fā)送信號(hào),觸發(fā)線程工作
void operate1(const int);
};
#endif // CONTROLLER_H
通過觸發(fā)信號(hào)和工作的槽函數(shù)連接起來,啟動(dòng)線程,觸發(fā)信號(hào),線程就執(zhí)行了。
#include "controller.h"
Controller::Controller(QObject *parent)
: QObject{parent}
{
//工作類實(shí)例化
auto *worker = new work;
//將worker對(duì)象的事件循環(huán)全部交由workerThread線程
worker->moveToThread(&workerThread);
//觸發(fā)信號(hào),開始工作。
connect(this,&Controller::operate1,worker,&work::dowork);
//線程執(zhí)行完成發(fā)出信號(hào),接收信號(hào)執(zhí)行下一個(gè)動(dòng)作;
connect(worker,&work::resultReady,this,&Controller::handleResults);
//線程結(jié)束時(shí)候銷毀
connect(&workerThread,&QThread::finished,worker,&QThread::deleteLater);
//啟動(dòng)線程
workerThread.start();
//觸發(fā)線程工作
emit operate1(0);
}
Controller::~Controller()
{
workerThread.quit();
workerThread.wait();
}
void Controller::handleResults(int result)
{
qDebug() << "receive the resultReady signal" ;
qDebug() << "\tCurrent thread ID: " << QThread::currentThreadId() << '\n' ;
qDebug() << "\tThe last result is: " << result ;
}