实现步骤
-
创建工作类 (
Worker
):在工作线程中处理数据的对象。 -
创建线程对象 (
QThread
):用来托管工作对象。 -
连接信号槽:
-
主线程 -> 工作线程 :连接一个主窗口发出的信号 到工作对象的槽,用于传递数据。
-
工作线程 -> 主线程 :连接工作对象发出的信号 到主窗口的槽,用于返回结果、更新UI。
-
-
移动工作对象:将工作对象移动到新线程。
-
启动线程:启动线程的事件循环。
-
按钮点击 :在按钮点击的槽函数中,发射那个用于传递数据的信号。
完整代码示例
1. 工作类 (worker.h)
cpp
// worker.h
#ifndef WORKER_H
#define WORKER_H
#include <QObject>
#include <QString>
#include <QDebug>
#include <QThread>
class Worker : public QObject
{
Q_OBJECT
public:
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)
cpp
// mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
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) - 核心
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();
// 初始化UI
ui->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); // 重新启用按钮
}