当遇到非常复杂的数据处理时,可以开个线程

4.7以前版本方法

image.png
image.png

mythread.h

  1. #ifndef MYTHREAD_H
  2. #define MYTHREAD_H
  3. #include <QThread>
  4. class MyThread : public QThread
  5. {
  6. Q_OBJECT
  7. public:
  8. explicit MyThread(QObject *parent = nullptr);
  9. protected:
  10. // QThread的虚函数
  11. // 线程处理函数
  12. // 不能直接调用,通过start()间接调用
  13. void run();
  14. signals:
  15. void isDone();
  16. public slots:
  17. };
  18. #endif // MYTHREAD_H

mythread.cpp

  1. #include "mythread.h"
  2. MyThread::MyThread(QObject *parent) : QThread(parent)
  3. {
  4. }
  5. void MyThread::run()
  6. {
  7. // 模拟很复杂的数据需要耗时5s
  8. sleep(5);
  9. // 处理完后发送信号
  10. emit isDone();
  11. }

therad.h

  1. #ifndef THERAD_H
  2. #define THERAD_H
  3. #include <QWidget>
  4. #include <QTimer>
  5. #include "mythread.h" // 线程头文件
  6. namespace Ui {
  7. class Therad;
  8. }
  9. class Therad : public QWidget
  10. {
  11. Q_OBJECT
  12. public:
  13. explicit Therad(QWidget *parent = 0);
  14. ~Therad();
  15. void dealTimeout(); // 定时器槽函数
  16. void dealDone(); // 线程结束槽函数
  17. void closeThread(); // 关闭线程槽函数
  18. private slots:
  19. void on_pushButton_clicked();
  20. private:
  21. Ui::Therad *ui;
  22. QTimer *myTimer; // 声明变量
  23. MyThread *thread; // 线程对象
  24. };
  25. #endif // THERAD_H

therad.cpp

  1. #include "therad.h"
  2. #include "ui_therad.h"
  3. #include <QDebug>
  4. Therad::Therad(QWidget *parent) :
  5. QWidget(parent),
  6. ui(new Ui::Therad)
  7. {
  8. ui->setupUi(this);
  9. myTimer = new QTimer(this);
  10. connect(myTimer, &QTimer::timeout, this, &Therad::dealTimeout);
  11. // 分配空间
  12. thread = new MyThread(this);
  13. connect(thread, &MyThread::isDone, this, &Therad::dealDone);
  14. // 当按窗口右上角关闭按钮时触发destroyed()
  15. connect(this, &Therad::destroyed, this, &Therad::closeThread);
  16. }
  17. // 关闭线程
  18. void Therad::closeThread()
  19. {
  20. // 退出子线程
  21. thread->quit();
  22. // 等待线程处理完手头动作
  23. 回收资源
  24. thread->wait();
  25. }
  26. // 处理完成
  27. void Therad::dealDone()
  28. {
  29. qDebug() << "it is over";
  30. myTimer->stop(); // 关闭定时器
  31. }
  32. void Therad::dealTimeout()
  33. {
  34. static int i = 0;
  35. i++;
  36. // 设置lcd的值
  37. ui->lcdNumber->display(i);
  38. }
  39. Therad::~Therad()
  40. {
  41. delete ui;
  42. }
  43. void Therad::on_pushButton_clicked()
  44. {
  45. // 如果定时器没工作
  46. if(myTimer->isActive() == false)
  47. {
  48. myTimer->start(100);
  49. }
  50. // 启动线程,处理数据
  51. thread->start();
  52. }

5.*版本方法

image.png
image.png

mythread.h

  1. #ifndef MYTHREAD_H
  2. #define MYTHREAD_H
  3. #include <QObject>
  4. class MyThread : public QObject
  5. {
  6. Q_OBJECT
  7. public:
  8. explicit MyThread(QObject *parent = nullptr);
  9. // 线程处理函数
  10. void myTimeout();
  11. void setFlag(bool flag = true); // 槽函数,处理标志位
  12. bool isStop = false; // 标志位
  13. signals:
  14. void mySignal();
  15. public slots:
  16. };
  17. #endif // MYTHREAD_H

mythread.cpp

  1. #include "mythread.h"
  2. #include <QThread>
  3. #include <QDebug>
  4. MyThread::MyThread(QObject *parent) : QObject(parent)
  5. {
  6. }
  7. // 线程处理函数
  8. void MyThread::myTimeout()
  9. {
  10. // isStop为false时进入循环
  11. while(isStop == false)
  12. {
  13. QThread::sleep(1); // 模拟延迟1s
  14. emit mySignal(); // 触发信号
  15. qDebug() << "子线程号:" << QThread::currentThread();
  16. // isStop为true时跳出循环
  17. if(isStop == true)
  18. {
  19. break;
  20. }
  21. }
  22. }
  23. // 槽函数,处理标志位
  24. void MyThread::setFlag(bool flag)
  25. {
  26. isStop = flag;
  27. }

mywindow.h

  1. #ifndef MYWINDOW_H
  2. #define MYWINDOW_H
  3. #include <QWidget>
  4. #include "mythread.h"
  5. #include <QThread>
  6. namespace Ui {
  7. class MyWindow;
  8. }
  9. class MyWindow : public QWidget
  10. {
  11. Q_OBJECT
  12. public:
  13. explicit MyWindow(QWidget *parent = 0);
  14. ~MyWindow();
  15. void dealSignal(); // 接收信号并处理
  16. signals:
  17. void startThread(); // 启动子线程的信号
  18. private slots:
  19. void on_buttonStart_clicked();
  20. void on_buttonStop_clicked();
  21. private:
  22. Ui::MyWindow *ui;
  23. MyThread *myT; // 创建线程指针
  24. QThread *thread; // 创建子线程指针
  25. };
  26. #endif // MYWINDOW_H

mywindow.cpp

  1. #include "mywindow.h"
  2. #include "ui_mywindow.h"
  3. #include <QDebug>
  4. MyWindow::MyWindow(QWidget *parent) :
  5. QWidget(parent),
  6. ui(new Ui::MyWindow)
  7. {
  8. ui->setupUi(this);
  9. // 动态分配空间,不能指定父对象
  10. myT = new MyThread;
  11. // 创建子线程
  12. thread = new QThread(this);
  13. // 把自定义线程加入到子线程中
  14. myT->moveToThread(thread);
  15. connect(myT, &MyThread::mySignal, this, &MyWindow::dealSignal);
  16. qDebug() << "主线程号:" << QThread::currentThread();
  17. // 连接信号和槽
  18. connect(this, &MyWindow::startThread, myT, &MyThread::myTimeout);
  19. // 窗口关闭后关闭线程
  20. connect(this, &MyWindow::destroyed, this, [=](){
  21. on_buttonStop_clicked();
  22. delete myT;
  23. });
  24. }
  25. MyWindow::~MyWindow()
  26. {
  27. delete ui;
  28. }
  29. // 接收信号并处理
  30. void MyWindow::dealSignal()
  31. {
  32. static int i = 0;
  33. i++;
  34. ui->lcdNumber->display(i);
  35. }
  36. void MyWindow::on_buttonStart_clicked()
  37. {
  38. // 线程正在运行的时候不再进入
  39. if(thread->isRunning() == true)
  40. {
  41. return;
  42. }
  43. // 启动线程,但是没有启动线程处理函数
  44. thread->start();
  45. myT->setFlag(false); // 设置标志位为false
  46. // 不能直接调用线程处理函数
  47. // 直接调用将导致线程处理函数和主线程在同一个线程
  48. // myT->myTimeout();
  49. // 只能通过 signal - slot 方式调用
  50. emit startThread();
  51. }
  52. // 关闭线程
  53. void MyWindow::on_buttonStop_clicked()
  54. {
  55. // 线程已经关闭的时候不再进入
  56. if(thread->isRunning() == false)
  57. {
  58. return;
  59. }
  60. myT->setFlag(true); // 设置标志位为true
  61. thread->quit(); // 退出子线程
  62. thread->wait(); //回收资源
  63. }

注意:
线程处理函数内部,不允许操作图形界面
connect() 第五个参数的作用, 连接方式:默认,队列,直接
多线程时才有意义
默认的时候,如果是多线程,默认使用队列,如果是单线程,默认使用直接方式
队列:槽函数所在的线程和接收者一样;直接:槽函数所在线程和发送者一样