1024程序员快乐,如果这博客让你学习到了知识,请给我一个免费的赞❤️
父子线程演示
一、创建界面文件
LCDnumber
二、创建mythread类,继承QObject
三、在MyThread.h文件做修改,并且加上函数声明
引入头文件,改变继承
#ifndef MYTHREAD_H
#define MYTHREAD_H#include <QThread>class MyThread : public QThread
{Q_OBJECT
public:explicit MyThread(QObject *parent = 0);protected:void run(); // 入口函数 -- 需要start()启动signals:void sigDone();public slots:
};#endif // MYTHREAD_H
四、实现run方法
#include "mythread.h"MyThread::MyThread(QObject *parent) : QThread(parent)
{}void MyThread::run()
{// 模拟复杂的操作sleep(5); //休眠5semit sigDone();
}
五、使用计时器来控制LCDnumber
//计时器mytimer = new QTimer(this);myt = new MyThread(this);connect(mytimer, &QTimer::timeout, this, [=](){static int num = 0;ui->lcdNumber->display(num++);});
六、实现按钮的槽函数
void MyWidget::on_begin_clicked()
{//如果计时器开着if(mytimer->isActive() == true){return;}// 启动定时器mytimer->start(1000); // ms// 启动子线程myt->start();
}
子线程运行结束后,停止计数器
// 子线程信号,子线程运行结束停止计数器
connect(myt, &MyThread::finished, mytimer, &QTimer::stop);
完整代码
mythread.cpp
#include "mythread.h"MyThread::MyThread(QObject *parent) : QThread(parent)
{}void MyThread::run()
{// 模拟复杂的操作sleep(5); //休眠5semit sigDone();
}
mythread.h
#ifndef MYTHREAD_H
#define MYTHREAD_H#include <QThread>class MyThread : public QThread
{Q_OBJECT
public:explicit MyThread(QObject *parent = 0);protected:void run(); // 入口函数 -- 需要start()启动signals:void sigDone();public slots:
};#endif // MYTHREAD_H
mywidget.cpp
#include "mywidget.h"
#include "ui_mywidget.h"
#include <QThread>
#include <QDebug>MyWidget::MyWidget(QWidget *parent) :QWidget(parent),ui(new Ui::MyWidget)
{ui->setupUi(this);//计时器mytimer = new QTimer(this);myt = new MyThread(this);connect(mytimer, &QTimer::timeout, this, [=](){static int num = 0;ui->lcdNumber->display(num++);});// 子线程信号,子线程运行结束停止计数器connect(myt, &MyThread::finished, mytimer, &QTimer::stop);}MyWidget::~MyWidget()
{delete ui;
}void MyWidget::on_begin_clicked()
{//如果计时器开着if(mytimer->isActive() == true){return;}// 启动定时器mytimer->start(1000); // ms// 启动子线程myt->start();
}
mywidget.h
#ifndef MYWIDGET_H
#define MYWIDGET_H#include <QWidget>
#include <QTimer>
#include "mythread.h"namespace Ui {
class MyWidget;
}class MyWidget : public QWidget
{Q_OBJECTpublic:explicit MyWidget(QWidget *parent = 0);~MyWidget();private slots:void on_begin_clicked();private:Ui::MyWidget *ui;QTimer* mytimer;MyThread *myt;
};#endif // MYWIDGET_H
多线程演示
一、创建界面文件
LCDnumber
二、创建子线程Mywork类,继承QObject
三、在mywork.h文件加上函数声明,成员变量
#ifndef MYWORK_H
#define MYWORK_H#include <QObject>class MyWork : public QObject
{Q_OBJECT
public:explicit MyWork(QObject *parent = 0);// 业务处理函数void doMyWork();void setFlag(bool bl);signals:
public slots:private:bool isStop;
};#endif // MYWORK_H
四、父线程mywidget.h实现
引入头文件(包括子线程的头文件)、信号函数、槽函数
#ifndef MYWIDGET_H
#define MYWIDGET_H#include <QThread>
#include <QTimer>
#include <QWidget>
#include "mywork.h"namespace Ui {
class MyWidget;
}class MyWidget : public QWidget
{Q_OBJECTpublic:explicit MyWidget(QWidget *parent = 0);~MyWidget();signals:// 发信号, 让子线程工作void sigWorking();public slots:// 开始按钮void slotStart();// 关闭按钮void slotStop();// 定时器void slotTimeout();// 关闭线程void slotCloseThread();private:Ui::MyWidget *ui;QTimer *mytimer;MyWork *work;QThread *pthread; //子线程
};#endif // MYWIDGET_H
五、实现子线程mywork.cpp
比较简单、模拟线程处理作业
#include "mywork.h"
#include <QThread>
#include <QMessageBox>
#include <QDebug>MyWork::MyWork(QObject *parent) : QObject(parent)
{isStop = false;
}void MyWork::doMyWork()
{while(!isStop){// 操作QThread::sleep(1); // 当前线程处理操作用了1s// 每执行一次循环发一次信号qDebug() << QThread::currentThread() << "sub thread";// QMessageBox::aboutQt(NULL);}
}void MyWork::setFlag(bool bl)
{isStop = bl;
}
六、实现mywidget.cpp
多线程使用注意事项:
* 1. 业务对象, 构造的时候不能指定父对象
* 2. 子线程中不能处理ui窗口(ui相关的类)
* 3. 子线程中只能处理一些数据相关的操作, 不能涉及窗口
不建议在析构函数中进行与线程相关的操作。析构函数通常用于以下几种情况:
- 使用
new
分配的内存需要使用delete
释放动态分配的资源。 - 关闭文件或网络连接
- 断开信号和槽连接
- 日志记录与打印
/* 多线程使用注意事项:* 1. 业务对象, 构造的时候不能指定父对象* 2. 子线程中不能处理ui窗口(ui相关的类)* 3. 子线程中只能处理一些数据相关的操作, 不能涉及窗口*/mytimer = new QTimer(this);// 1. 业务对象work = new MyWork();// 2. 子线程类pthread = new QThread(this);// 3. 移动业务对象到子线程work->moveToThread(pthread);// 5. 子线程工作connect(this, &MyWidget::sigWorking, work, &MyWork::doMyWork);connect(ui->start, &QPushButton::clicked, this, &MyWidget::slotStart);connect(ui->stop, &QPushButton::clicked, this, &MyWidget::slotStop);// 定时器connect(mytimer, &QTimer::timeout, this, &MyWidget::slotTimeout);// 窗口析构的时候干掉线程connect(this, &MyWidget::destroyed, this, &MyWidget::slotCloseThread);qDebug() << QThread::currentThread() << "main thread";void MyWidget::slotStart()
{if(mytimer->isActive() == true){return;}if(pthread->isRunning()){return;}mytimer->start(500);// 4. 启动子线程pthread->start();// 发信号, 让子线程工作emit sigWorking();
}void MyWidget::slotStop()
{if(mytimer->isActive() == false){return;}mytimer->stop();// 停止子线程pthread->quit();work->setFlag(true);
}void MyWidget::slotTimeout()
{static int num = 0;ui->lcdNumber->display(num++);
}
// 窗口析构的时候干掉线程
void MyWidget::slotCloseThread()
{work->setFlag(true);pthread->quit();pthread->wait(); // 等待线程手头上的工作处理完成
}
完整代码
mywork.cpp
#include "mywork.h"
#include <QThread>
#include <QMessageBox>
#include <QDebug>MyWork::MyWork(QObject *parent) : QObject(parent)
{isStop = false;
}void MyWork::doMyWork()
{while(!isStop){// 操作QThread::sleep(1); // 当前线程处理操作用了1s// 每执行一次循环发一次信号qDebug() << QThread::currentThread() << "sub thread";// QMessageBox::aboutQt(NULL);}
}void MyWork::setFlag(bool bl)
{isStop = bl;
}
mywork.h
#ifndef MYWORK_H
#define MYWORK_H#include <QObject>class MyWork : public QObject
{Q_OBJECT
public:explicit MyWork(QObject *parent = 0);// 业务处理函数void doMyWork();void setFlag(bool bl);signals:
public slots:private:bool isStop;
};#endif // MYWORK_H
mywidget.h
#ifndef MYWIDGET_H
#define MYWIDGET_H#include <QThread>
#include <QTimer>
#include <QWidget>
#include "mywork.h"namespace Ui {
class MyWidget;
}class MyWidget : public QWidget
{Q_OBJECTpublic:explicit MyWidget(QWidget *parent = 0);~MyWidget();signals:// 发信号, 让子线程工作void sigWorking();public slots:// 开始按钮void slotStart();// 关闭按钮void slotStop();// 定时器void slotTimeout();// 关闭线程void slotCloseThread();private:Ui::MyWidget *ui;QTimer *mytimer;MyWork *work;QThread *pthread; //子线程
};#endif // MYWIDGET_H
mywidget.cpp
#include "mywidget.h"
#include "ui_mywidget.h"
#include <QDebug>MyWidget::MyWidget(QWidget *parent) : QWidget(parent),ui(new Ui::MyWidget)
{ui->setupUi(this);/* 多线程使用注意事项:* 1. 业务对象, 构造的时候不能指定父对象* 2. 子线程中不能处理ui窗口(ui相关的类)* 3. 子线程中只能处理一些数据相关的操作, 不能涉及窗口*/mytimer = new QTimer(this);// 1. 业务对象work = new MyWork();// 2. 子线程类pthread = new QThread(this);// 3. 移动业务对象到子线程work->moveToThread(pthread);// 5. 子线程工作connect(this, &MyWidget::sigWorking, work, &MyWork::doMyWork);connect(ui->start, &QPushButton::clicked, this, &MyWidget::slotStart);connect(ui->stop, &QPushButton::clicked, this, &MyWidget::slotStop);// 定时器connect(mytimer, &QTimer::timeout, this, &MyWidget::slotTimeout);// 窗口析构的时候干掉线程connect(this, &MyWidget::destroyed, this, &MyWidget::slotCloseThread);qDebug() << QThread::currentThread() << "main thread";/* connect 的第 5 参数* 1. 自动连接 -- 默认* 多线程 -- 指定队列连接* 单线程 -- 指定直接连接* 2. 队列连接 -- 多线程* 槽函数在信号接受者(receiver)所在的线程中执行* 3. 直接连接 -- 单线程* 信号和槽函数在同一个线程中执行*/
}MyWidget::~MyWidget()
{delete ui;
}void MyWidget::slotStart()
{if(mytimer->isActive() == true){return;}if(pthread->isRunning()){return;}mytimer->start(500);// 4. 启动子线程pthread->start();// 发信号, 让子线程工作emit sigWorking();
}void MyWidget::slotStop()
{if(mytimer->isActive() == false){return;}mytimer->stop();// 停止子线程pthread->quit();work->setFlag(true);
}void MyWidget::slotTimeout()
{static int num = 0;ui->lcdNumber->display(num++);
}
// 窗口析构的时候干掉线程
void MyWidget::slotCloseThread()
{work->setFlag(true);pthread->quit();pthread->wait(); // 等待线程手头上的工作处理完成
}