實現步驟
創建工作類?(
Worker
):在工作線程中處理數據的對象。創建線程對象?(
QThread
):用來托管工作對象。連接信號槽:
主線程 -> 工作線程:連接一個主窗口發出的信號到工作對象的槽,用于傳遞數據。
工作線程 -> 主線程:連接工作對象發出的信號到主窗口的槽,用于返回結果、更新UI。
移動工作對象:將工作對象移動到新線程。
啟動線程:啟動線程的事件循環。
按鈕點擊:在按鈕點擊的槽函數中,發射那個用于傳遞數據的信號。
完整代碼示例
1. 工作類 (worker.h)
// worker.h
#ifndef WORKER_H
#define WORKER_H#include <QObject>
#include <QString>
#include <QDebug>
#include <QThread>class Worker : public QObject
{Q_OBJECTpublic:explicit Worker(QObject *parent = nullptr) : QObject(parent) {}public slots:// 這個槽函數專門用來接收主線程發來的數據并進行處理void handleDataFromMainThread(const QString &data) {qDebug() << "工作線程ID:" << QThread::currentThreadId();qDebug() << "收到主線程發來的數據:" << data;// 模擬一個耗時的數據處理過程QString result;for (int i = 0; i < data.length(); ++i) {QThread::msleep(200); // 模擬處理每個字符需要時間result.prepend(data[i]); // 做一個簡單的反轉操作作為處理示例emit progress(i+1, data.length()); // 發送處理進度}// 處理完成,發射信號將結果發回主線程emit dataProcessed(result);}signals:// 處理進度信號 (當前進度, 總數)void progress(int current, int total);// 處理完成信號 (結果)void dataProcessed(const QString &result);
};#endif // WORKER_H
2. 主窗口頭文件 (mainwindow.h)
// mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACEclass MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();// 新增一個信號,用于向工作線程發送數據
signals:void sendDataToWorker(const QString &data);private slots:// 按鈕點擊的槽函數void on_pushButtonStart_clicked();// 接收工作線程發回的信號的槽函數void updateProgress(int current, int total);void handleResult(const QString &result);private:Ui::MainWindow *ui;QThread *workerThread;
};#endif // MAINWINDOW_H
3. 主窗口實現 (mainwindow.cpp) - 核心
// mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "worker.h" // 包含工作類頭文件
#include <QThread>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow), workerThread(new QThread(this)) // 線程對象的父對象是主窗口,生命周期由其管理
{ui->setupUi(this);// 創建工作者對象,此時它還在主線程Worker *worker = new Worker;// !!! 關鍵步驟:將工作者對象移動到新線程 !!!worker->moveToThread(workerThread);// !!! 核心連接:主線程 -> 工作線程 !!!// 當主窗口發射 sendDataToWorker 信號時, worker 的 handleDataFromMainThread 槽函數會被調用// 因為 worker 已移動到新線程,這個連接會自動使用 QueuedConnection,保證線程安全connect(this, &MainWindow::sendDataToWorker, worker, &Worker::handleDataFromMainThread);// 連接:工作線程 -> 主線程 (用于更新UI)connect(worker, &Worker::progress, this, &MainWindow::updateProgress);connect(worker, &Worker::dataProcessed, this, &MainWindow::handleResult);// 連接線程結束信號,用于自動清理對象connect(workerThread, &QThread::finished, worker, &QObject::deleteLater);connect(workerThread, &QThread::finished, workerThread, &QObject::deleteLater);// 啟動線程(啟動事件循環)workerThread->start();// 初始化UIui->progressBar->setValue(0);
}MainWindow::~MainWindow()
{// 優雅退出線程if (workerThread && workerThread->isRunning()) {workerThread->quit();workerThread->wait();}delete ui;
}// 按鈕點擊事件
void MainWindow::on_pushButtonStart_clicked()
{QString inputData = ui->lineEditInput->text();if (inputData.isEmpty()) {return;}// 禁用按鈕,防止重復點擊ui->pushButtonStart->setEnabled(false);ui->progressBar->setValue(0);// !!! 核心操作:發射信號,將數據發送到工作線程 !!!qDebug() << "主線程ID:" << QThread::currentThreadId() << ",發射信號,數據:" << inputData;emit sendDataToWorker(inputData);
}// 更新進度條
void MainWindow::updateProgress(int current, int total)
{int percent = (current * 100) / total;ui->progressBar->setValue(percent);ui->labelStatus->setText(QString("處理中: %1/%2").arg(current).arg(total));
}// 顯示處理結果
void MainWindow::handleResult(const QString &result)
{ui->textEditResult->setText(result);ui->labelStatus->setText("處理完成!");ui->pushButtonStart->setEnabled(true); // 重新啟用按鈕
}