4.7以前版本方法
mythread.h
#ifndef MYTHREAD_H#define MYTHREAD_H#include <QThread>class MyThread : public QThread{Q_OBJECTpublic: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(){// 模拟很复杂的数据需要耗时5ssleep(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_OBJECTpublic: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_OBJECTpublic: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); // 模拟延迟1semit 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_OBJECTpublic: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); // 设置标志位为truethread->quit(); // 退出子线程thread->wait(); //回收资源}
注意:
线程处理函数内部,不允许操作图形界面
connect() 第五个参数的作用, 连接方式:默认,队列,直接
多线程时才有意义
默认的时候,如果是多线程,默认使用队列,如果是单线程,默认使用直接方式
队列:槽函数所在的线程和接收者一样;直接:槽函数所在线程和发送者一样


