繼承QThread的線程
繼承 QThread 是創建線程的一個普通方法。其中創建的線程只有 run() 方法在線程里的。其他類內定義的方法都在主線程內。

通過上面的圖我們可以看到,主線程內有很多方法在主線程內,但是子線程,只有 run() 方法是在子線程里的。 run() 方法是繼承于 QThread 類的方法,用戶需要重寫這個方法,一般是把耗時的操作寫在這個 run() 方法里面。
QThread 類繼承線程,然后在 MainWindow 類里使用。通過點擊一個按鈕開啟線程。當線程執行完成時,會發送 resultReady(const QString &s) 信號給主線程,代碼如下:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include <QThread>
#include <QDebug>
#include <QPushButton>class WorkerThread;class MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();private:QPushButton *pushButton;WorkerThread *workThread;private slots:void handleResults(const QString &result);void pushButtonClicked();
};class WorkerThread : public QThread
{Q_OBJECTpublic:WorkerThread(QWidget *parent = nullptr){Q_UNUSED(parent);}void run() override {QString result = "Thread Start";/** Timerout*/sleep(2);emit resultReady(result);}signals:void resultReady(const QString &s);
};
#endif // MAINWINDOW_H
#include "mainwindow.h"MainWindow::MainWindow(QWidget *parent): QMainWindow(parent)
{this->setGeometry(0,0,800,480);pushButton = new QPushButton(this);workThread = new WorkerThread(this);pushButton->resize(100,40);pushButton->setText("Start Thread");/* 信號槽連接 */connect(workThread, &WorkerThread::resultReady,this, &MainWindow::handleResults);connect(pushButton, &QPushButton::clicked,this, &MainWindow::pushButtonClicked);
}MainWindow::~MainWindow()
{workThread->quit();if(workThread->wait(2000)){qDebug() << "Thread end" << endl;}
}void MainWindow::handleResults(const QString &result)
{qDebug() << result << endl;
}void MainWindow::pushButtonClicked()
{if (!workThread->isRunning())workThread->start();
}
上述代碼很簡單,相信都能看懂。
主窗口構造函數:當創建 MainWindow 對象時,構造函數設置窗口尺寸,初始化按鈕和工作線程,并連接信號槽。
按鈕點擊事件:當用戶點擊按鈕時,調用 pushButtonClicked 槽函數,啟動線程。
線程執行:線程開始運行,暫停2秒,然后發出 resultReady 信號。
結果處理:信號槽機制確保 handleResults 槽函數被調用,輸出線程結果。
主窗口析構函數:在銷毀 MainWindow 對象時,確保線程被正確終止并釋放資源。
效果:
點擊開啟線程按鈕后,延時 2s 后, Qt Creator 的應用程序輸出窗口打印出“線程開啟成功”。
在 2s 內多次點擊按鈕則不會重復開啟線程,因為線程在這 2s 內還在運行。同時我們可以看到
點擊按鈕沒卡頓現象。因為這個延時操作是在我們創建的線程里運行的,而 pushButton 是在主
線程里的,通過點擊按鈕控制子線程的運行。
當關閉程序后,子線程將在主線程的析構函數里退出。注意線程使用 wait() 方法,這里等
待 2s ,因為我們開啟的線和是延時 2s 就完成了。如果是實際的操作,請根據 CPU 的處理能力,
給一個適合的延時,阻塞等待線程完成后,就會自動退出并打印“線程已經結束”。
繼承QObject的線程
#include "mainwindow.h"MainWindow::MainWindow(QWidget *parent): QMainWindow(parent)
{this->setGeometry(0,0,800,480);pushButton1 = new QPushButton(this);pushButton2 = new QPushButton(this);pushButton1->setGeometry(300, 200, 80, 40);pushButton2->setGeometry(400, 200, 80, 40);pushButton1->setText(" Start Thread ");pushButton2->setText(" failed Thread ");worker = new Worker;worker->moveToThread(&workerThread);/* 線程完成銷毀對象 */connect(&workerThread, SIGNAL(finished()),worker, SLOT(deleteLater()));connect(&workerThread, SIGNAL(finished()),&workerThread, SLOT(deleteLater()));/* 發送開始工作的信號,開始工作 */connect(this, SIGNAL(startWork(QString)),worker, SLOT(doWork1(QString)));/* 接收到 worker 發送過來的信號 */connect(worker, SIGNAL(resultReady(QString)),this, SLOT(handleResults(QString)));/* 點擊按鈕開始線程 */connect(pushButton1, SIGNAL(clicked()),this, SLOT(pushButton1Clicked()));/* 點擊按鈕打斷線程 */connect(pushButton2, SIGNAL(clicked()),this, SLOT(pushButton2Clicked()));
}MainWindow::~MainWindow()
{worker->stopwork();workerThread.quit();if(workerThread.wait(2000)){qDebug() << "Thread end" << endl;}
}void MainWindow::handleResults(const QString &result)
{qDebug() << result << endl;
}void MainWindow::pushButton1Clicked()
{const QString str = "";if (!workerThread.isRunning())workerThread.start();emit this->startWork(str);
}void MainWindow::pushButton2Clicked()
{if(workerThread.isRunning()){worker->stopwork();}
}
#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include <QThread>
#include <QDebug>
#include <QPushButton>
#include <QMutexLocker>
#include <QMutex>class Worker;class MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();private:QPushButton *pushButton1;QPushButton *pushButton2;QThread workerThread;Worker *worker;private slots:void handleResults(const QString &result);void pushButton1Clicked();void pushButton2Clicked();signals:void startWork(const QString &);
};class Worker : public QThread
{Q_OBJECTprivate:QMutex lock;bool isCanRun;public slots:void doWork1(const QString ¶meter){isCanRun = true;while(1){{QMutexLocker locker(&lock);if(!isCanRun){break;}}QThread::sleep(2);emit resultReady(parameter + " dowork1 thread ");}emit resultReady("stop work1 thread");}public:void stopwork(){qDebug() << "thread failed" << endl;QMutexLocker locker(&lock);isCanRun = false;}signals:void resultReady(const QString &result);
};
#endif // MAINWINDOW_H