4.7以前版本方法
mythread.h
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QThread>
class MyThread : public QThread
{
Q_OBJECT
public:
explicit MyThread(QObject *parent = nullptr);
protected:
// QThread的虚函数
// 线程处理函数
// 不能直接调用,通过start()间接调用
void run();
signals:
void isDone();
public slots:
};
#endif // MYTHREAD_H
mythread.cpp
#include "mythread.h"
MyThread::MyThread(QObject *parent) : QThread(parent)
{
}
void MyThread::run()
{
// 模拟很复杂的数据需要耗时5s
sleep(5);
// 处理完后发送信号
emit isDone();
}
therad.h
#ifndef THERAD_H
#define THERAD_H
#include <QWidget>
#include <QTimer>
#include "mythread.h" // 线程头文件
namespace Ui {
class Therad;
}
class Therad : public QWidget
{
Q_OBJECT
public:
explicit Therad(QWidget *parent = 0);
~Therad();
void dealTimeout(); // 定时器槽函数
void dealDone(); // 线程结束槽函数
void closeThread(); // 关闭线程槽函数
private slots:
void on_pushButton_clicked();
private:
Ui::Therad *ui;
QTimer *myTimer; // 声明变量
MyThread *thread; // 线程对象
};
#endif // THERAD_H
therad.cpp
#include "therad.h"
#include "ui_therad.h"
#include <QDebug>
Therad::Therad(QWidget *parent) :
QWidget(parent),
ui(new Ui::Therad)
{
ui->setupUi(this);
myTimer = new QTimer(this);
connect(myTimer, &QTimer::timeout, this, &Therad::dealTimeout);
// 分配空间
thread = new MyThread(this);
connect(thread, &MyThread::isDone, this, &Therad::dealDone);
// 当按窗口右上角关闭按钮时触发destroyed()
connect(this, &Therad::destroyed, this, &Therad::closeThread);
}
// 关闭线程
void Therad::closeThread()
{
// 退出子线程
thread->quit();
// 等待线程处理完手头动作
回收资源
thread->wait();
}
// 处理完成
void Therad::dealDone()
{
qDebug() << "it is over";
myTimer->stop(); // 关闭定时器
}
void Therad::dealTimeout()
{
static int i = 0;
i++;
// 设置lcd的值
ui->lcdNumber->display(i);
}
Therad::~Therad()
{
delete ui;
}
void Therad::on_pushButton_clicked()
{
// 如果定时器没工作
if(myTimer->isActive() == false)
{
myTimer->start(100);
}
// 启动线程,处理数据
thread->start();
}
5.*版本方法
mythread.h
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QObject>
class MyThread : public QObject
{
Q_OBJECT
public:
explicit MyThread(QObject *parent = nullptr);
// 线程处理函数
void myTimeout();
void setFlag(bool flag = true); // 槽函数,处理标志位
bool isStop = false; // 标志位
signals:
void mySignal();
public slots:
};
#endif // MYTHREAD_H
mythread.cpp
#include "mythread.h"
#include <QThread>
#include <QDebug>
MyThread::MyThread(QObject *parent) : QObject(parent)
{
}
// 线程处理函数
void MyThread::myTimeout()
{
// isStop为false时进入循环
while(isStop == false)
{
QThread::sleep(1); // 模拟延迟1s
emit mySignal(); // 触发信号
qDebug() << "子线程号:" << QThread::currentThread();
// isStop为true时跳出循环
if(isStop == true)
{
break;
}
}
}
// 槽函数,处理标志位
void MyThread::setFlag(bool flag)
{
isStop = flag;
}
mywindow.h
#ifndef MYWINDOW_H
#define MYWINDOW_H
#include <QWidget>
#include "mythread.h"
#include <QThread>
namespace Ui {
class MyWindow;
}
class MyWindow : public QWidget
{
Q_OBJECT
public:
explicit MyWindow(QWidget *parent = 0);
~MyWindow();
void dealSignal(); // 接收信号并处理
signals:
void startThread(); // 启动子线程的信号
private slots:
void on_buttonStart_clicked();
void on_buttonStop_clicked();
private:
Ui::MyWindow *ui;
MyThread *myT; // 创建线程指针
QThread *thread; // 创建子线程指针
};
#endif // MYWINDOW_H
mywindow.cpp
#include "mywindow.h"
#include "ui_mywindow.h"
#include <QDebug>
MyWindow::MyWindow(QWidget *parent) :
QWidget(parent),
ui(new Ui::MyWindow)
{
ui->setupUi(this);
// 动态分配空间,不能指定父对象
myT = new MyThread;
// 创建子线程
thread = new QThread(this);
// 把自定义线程加入到子线程中
myT->moveToThread(thread);
connect(myT, &MyThread::mySignal, this, &MyWindow::dealSignal);
qDebug() << "主线程号:" << QThread::currentThread();
// 连接信号和槽
connect(this, &MyWindow::startThread, myT, &MyThread::myTimeout);
// 窗口关闭后关闭线程
connect(this, &MyWindow::destroyed, this, [=](){
on_buttonStop_clicked();
delete myT;
});
}
MyWindow::~MyWindow()
{
delete ui;
}
// 接收信号并处理
void MyWindow::dealSignal()
{
static int i = 0;
i++;
ui->lcdNumber->display(i);
}
void MyWindow::on_buttonStart_clicked()
{
// 线程正在运行的时候不再进入
if(thread->isRunning() == true)
{
return;
}
// 启动线程,但是没有启动线程处理函数
thread->start();
myT->setFlag(false); // 设置标志位为false
// 不能直接调用线程处理函数
// 直接调用将导致线程处理函数和主线程在同一个线程
// myT->myTimeout();
// 只能通过 signal - slot 方式调用
emit startThread();
}
// 关闭线程
void MyWindow::on_buttonStop_clicked()
{
// 线程已经关闭的时候不再进入
if(thread->isRunning() == false)
{
return;
}
myT->setFlag(true); // 设置标志位为true
thread->quit(); // 退出子线程
thread->wait(); //回收资源
}
注意:
线程处理函数内部,不允许操作图形界面
connect() 第五个参数的作用, 连接方式:默认,队列,直接
多线程时才有意义
默认的时候,如果是多线程,默认使用队列,如果是单线程,默认使用直接方式
队列:槽函数所在的线程和接收者一样;直接:槽函数所在线程和发送者一样