2023-02-05 QT 線程實(shí)現(xiàn)和計(jì)時(shí)器使用

第一種方式創(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)接收。


實(shí)例

界面

通過繪制一個(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 ;

}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容