Qt 中的多线程主要是为了防止复杂耗时的操作阻塞主线程,导致界面卡死的问题。可以通过继承 QThread
类后,重写 run()
函数来实现。
一、 定义继承自 QThread
的类
定义一个类继承自 QThread
,并重写虚函数 run()
,将耗时的操作放在 run()
函数中,然后在主线程中来通过调用该类的 start()
函数,从而实现启动子线程执行 run()
函数中的内容。
1、 定义继承自 QThread
类 WorkThread
,作为子线程
WorkThread.h
内容如下:
#pragma once
#include <QThread>
/// <summary>
/// 通过继承 QThread类,并重写 run 函数来实现多线程操作,
/// 将复杂的操作放在run函数里面,run()函数相当于运行在一个新的线程中。
/// 需要公有继承 QThread 类,否则后面无法调用重载的 run 函数
/// </summary>
class WorkThread: public QThread
{
Q_OBJECT
public:
WorkThread();
~WorkThread();
/**
* @brief 在该函数中实现耗时阻塞主线程的操作,该函数中的操作将会在子线程中执行
*/
void run() override;
signals:
/**
* 子线程无法直接操作UI,因此只能通过信号槽的机制来向主线程发送信号,
* 主线程接受到该信号后,进行更新UI内容,从而实现间接操作UI.
*/
void SendMsg(QString msg);
};
WorkThread.cpp
内容如下:
#include "WorkThread.h"
WorkThread::WorkThread()
{
}
WorkThread::~WorkThread()
{
// 使用quit()或者exit()使得子线程能够退出消息循环,而不会一直阻塞在子线程中
this->quit();
// 等待子线程退出后,回收子线程的资源
this->wait();
}
void WorkThread::run()
{
int curId = (int)QThread::currentThreadId();
emit SendMsg(QString("子线程id = %1").arg(curId));
emit SendMsg("Start do something ...");
QThread::sleep(10);
QString resStr = "Finish complex operation";
emit SendMsg(resStr);
// 子线程中的消息循环函数,如果没有该函数,则子线程执行完后会立即退出
// this->exec();
}
2、在主线程中调用子线程
QThreadTest.h
内容如下:
#pragma once
#include <QtWidgets/QMainWindow>
#include "ui_QThreadTest.h"
#include "WorkThread.h"
class QThreadTest : public QMainWindow
{
Q_OBJECT
public:
QThreadTest(QWidget *parent = Q_NULLPTR);
~QThreadTest();
private slots:
/**
* 直接在主线程中进行耗时操作,会直接阻塞主UI线程,导致程序卡死.
*/
void OnBtn01Clicked();
/**
* @brief 将创建一个线程来执行复杂的操作,避免阻塞UI线程。
* 该类继承自 QThread,将复杂的操作写在 run()中,
* run()函数中的内容才会在子线程中执行。
*/
void OnBtn02Clicked();
/**
* @brief 由于子线程不能直接操作UI,所以该函数用于将接受到的子线程内容显示在UI上
* @param [in] msg
*/
void GetResult(QString msg);
private:
Ui::QThreadTestClass ui;
WorkThread* workThread; // 子线程的对象指针
};
QThreadTest.cpp
内容如下:
#include "QThreadTest.h"
#include <QPushButton>
QThreadTest::QThreadTest(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
// 在构造函数中初始化子线程的对象指针
workThread = new WorkThread();
// 子线程只能通过信号槽来间接的修改UI的内容
connect(workThread, &WorkThread::SendMsg, this, &QThreadTest::GetResult);
// 子线程结束之后释放其所占用的资源
connect(workThread, &WorkThread::finished, workThread, &WorkThread::deleteLater);
connect(ui.btn01, &QPushButton::clicked, this, &QThreadTest::OnBtn01Clicked);
connect(ui.btn02, &QPushButton::clicked, this, &QThreadTest::OnBtn02Clicked);
}
QThreadTest::~QThreadTest()
{
}
void QThreadTest::OnBtn01Clicked()
{
ui.textBrowser_01->append("Start do something ...");
QThread::sleep(5);
ui.textBrowser_01->append("Finishing this operation.");
}
void QThreadTest::OnBtn02Clicked()
{
ui.textBrowser_02->append(QString("主线程id = %1").arg((int)QThread::currentThreadId()));
// 启动子线程,开始执行 run 函数中的耗时操作,避免阻塞主线程。
workThread->start();
}
void QThreadTest::GetResult(QString msg)
{
ui.textBrowser_02->append("workThread: " + msg);
}
效果如下图所示:
点击 Btn01
后直接导致程序卡住,无法响应其它的操作。点击Btn02
后会在子线程中执行耗时操作,此时主 UI 线程仍然可以响应用户的操作,不会阻塞主线程。
【注意】
标签:run,Qt,QThreadTest,线程,WorkThread,多线程,QThread,函数 From: https://www.cnblogs.com/Jeffxu/p/17925023.html