00. 目录
01. 概述
Qt在运行时会开启一个主线程,如果没有开启工作线程的话,所有界面上的操作都是在主线程,包括更新界面或者处理数据等操作。我们都知道如果处理数据比较多的话,最好是在单独开启一个线程来处理数据,这样就不会影响主线程的运行。
02. 开发环境
Windows系统:Windows10
Qt版本:Qt5.15或者Qt6
03. 实时更新UI(非信号与槽)
QT中不建议工作线程中更新界面。
workthread.h
#ifndef WORKTHREAD_H
#define WORKTHREAD_H
#include <QThread>
class MainWindow;
class QLabel;
class WorkThread : public QThread
{
Q_OBJECT
public:
WorkThread(QObject *parent);
~WorkThread();
void setObject(MainWindow *obj);
void setLabel(QLabel *l);
void stop();
protected:
void run();
private:
MainWindow *mainObject = nullptr;
QLabel *label = nullptr;
int i = 0;
volatile bool stopped = false;
};
#endif // WORKTHREAD_H
workthread.cpp
#include "workthread.h"
#include "mainwindow.h"
#include <QLabel>
#include <QDebug>
WorkThread::WorkThread(QObject *parent):QThread(parent)
{
stopped = false;
}
WorkThread::~WorkThread()
{
}
void WorkThread::setObject(MainWindow *obj)
{
mainObject = obj;
}
void WorkThread::setLabel(QLabel *l)
{
label = l;
}
void WorkThread::run()
{
qDebug() << "线程开始运行";
while(!stopped)
{
msleep(1);
i++;
//mainObject->runInThread();
label->setText(QString("当前计数为:%1").arg(i));
}
//下次启动
stopped = false;
}
//暂停线程
void WorkThread::stop()
{
stopped = true;
qDebug() << "线程已经暂停";
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "workthread.h"
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class WorkThread;
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
void runInThread();
private slots:
void on_pushButton_clicked();
void on_pushButton_2_clicked();
private:
Ui::MainWindow *ui;
WorkThread *thread = nullptr;
int count = 0;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "workthread.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
thread = new WorkThread(this);
thread->setObject(this);
thread->setLabel(ui->label);
ui->pushButton->setEnabled(true);
ui->pushButton_2->setEnabled(false);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::runInThread()
{
count++;
ui->label->setText(QString("当前计数为: %1").arg(count));
}
//启动线程
void MainWindow::on_pushButton_clicked()
{
if (nullptr != thread)
{
thread->start();
}
ui->pushButton->setEnabled(false);
ui->pushButton_2->setEnabled(true);
}
//暂停线程
void MainWindow::on_pushButton_2_clicked()
{
if (nullptr != thread)
{
thread->stop();
}
ui->pushButton->setDisabled(false);
ui->pushButton_2->setDisabled(true);
}
主界面
04. 实时更新UI(信号与槽)
workthread.h
#ifndef WORKTHREAD_H
#define WORKTHREAD_H
#include <QThread>
class MainWindow;
class QLabel;
struct Student
{
int id;
char sex;
QString name;
};
//声明元类型
Q_DECLARE_METATYPE(Student)
class WorkThread : public QThread
{
Q_OBJECT
public:
WorkThread(QObject *parent);
~WorkThread();
void stop();
protected:
void run();
signals:
void sigCount(Student s);
private:
int i = 0;
volatile bool stopped = false;
};
#endif // WORKTHREAD_H
workthread.cpp
#include "workthread.h"
#include "mainwindow.h"
#include <QLabel>
#include <QDebug>
WorkThread::WorkThread(QObject *parent):QThread(parent)
{
//注册自定义类型
qRegisterMetaType<Student>();
stopped = false;
}
WorkThread::~WorkThread()
{
}
void WorkThread::run()
{
qDebug() << "线程开始运行";
while(!stopped)
{
i++;
//发送信号
Student s;
s.id = i;
s.sex = 'M';
s.name = "lily";
emit sigCount(s);
msleep(1);
}
//下次启动
stopped = false;
}
//暂停线程
void WorkThread::stop()
{
stopped = true;
qDebug() << "线程已经暂停";
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "workthread.h"
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class WorkThread;
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_pushButton_clicked();
void on_pushButton_2_clicked();
void slotSetValue(Student s);
private:
Ui::MainWindow *ui;
WorkThread *thread = nullptr;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "workthread.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
thread = new WorkThread(this);
ui->pushButton->setEnabled(true);
ui->pushButton_2->setEnabled(false);
connect(thread, &WorkThread::sigCount, this, &MainWindow::slotSetValue);
}
MainWindow::~MainWindow()
{
delete ui;
}
//启动线程
void MainWindow::on_pushButton_clicked()
{
if (nullptr != thread)
{
thread->start();
}
ui->pushButton->setEnabled(false);
ui->pushButton_2->setEnabled(true);
}
//暂停线程
void MainWindow::on_pushButton_2_clicked()
{
if (nullptr != thread)
{
thread->stop();
}
ui->pushButton->setDisabled(false);
ui->pushButton_2->setDisabled(true);
}
//槽函数
void MainWindow::slotSetValue(Student( s))
{
ui->label->setText(QString("当前值为: %1 %2 %3").arg(s.id).arg(s.sex).arg(s.name));
}
主界面
【温馨提示】
如果要在Qt信号槽中使用自定义类型,需要注意使用qRegisterMetaType对自定义类型进行注册,当然在不跨线程时使用自定义类型signal/slot来传递,可能不会出现什么问题;一旦涉及跨线程就很容易出错,回想下信号槽的作用就是用来对象与对象之间通信的,难免会跨线程,建议在使用自定义类型利用信号槽通信时,最好先通过qRegisterMetaType()将自定义类型进行注册,以免出错。
总结qRegisterMetaType使用方法如下:
1、注册位置:在第一次使用此类链接跨线程的signal/slot之前,一般在当前类的构造函数中进行注册;
2、注册方法:在当前类的顶部包含:#include ,构造函数中加入代码:qRegisterMetaType(“Myclass”);
3、Myclass的引用类型需单独注册:qRegisterMetaType(“Myclass&”);
05. 源码下载
06. 附录
6.1 Qt教程汇总
网址:https://dengjin.blog.csdn.net/article/details/115174639
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END
暂无评论内容