前言:
为什么要使用线程
什么时候用线程
复杂的数据处理
头文件.h
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QTimer>//定时器头文件QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();void dealTimeout();//定时器槽函数private slots:void on_pushButton_clicked();private:Ui::Widget *ui;QTimer *myTimer;//声明变量
};
#endif // WIDGET_H
.cpp文件
#include "widget.h"
#include "ui_widget.h"
#include <QThread>
#include <QDebug>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);myTimer=new QTimer(this);//只要定时器启动,自动触发timeout()connect(myTimer,&QTimer::timeout,this,&Widget::dealTimeout);
}void Widget::dealTimeout()
{static int i =0;i++;//设置LCD的值ui->lcdNumber->display(i);
}Widget::~Widget()
{delete ui;
}void Widget::on_pushButton_clicked()
{//如果定时器没有工作if(myTimer->isActive()==false){myTimer->start(100);}//非常复杂的数据处理,耗时较长QThread::sleep(5);//处理完数据,关闭定时器myTimer->stop();qDebug()<<"over";
}
现象
忘了录,而且不好展示,当按下start按键的时候,整个页面会卡住,不可移动和点击,LCD也没有变化,5秒后打印"over"
线程旧的用法
添加QThread文件
添加新文件
注意基类选择object
.h和.cpp文件改基类和头文件
运行检查是否有错
QThread F1查询 Protected Function
protected://QThread的虚函数//线程处理函数//不能直接调用,通过start()间接调用void run();
QThread的使用
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();};#endif // MYTHREAD_H
mythread.cpp 线程主文件
#include "mythread.h"MyThread::MyThread(QObject *parent) : QThread(parent)
{}void MyThread::run()
{//很复杂的数据处理//需要耗时5ssleep(5);emit isDone();
}
widget.h主窗口头文件
添加了线程头文件,线程槽函数,线程停止函数,线程对象
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QTimer>//定时器头文件
#include "mythread.h"//线程头文件QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();void dealTimeout();//定时器槽函数void dealDone();//线程槽函数void stopThread();//停止线程槽函数
private slots:void on_pushButton_clicked();private:Ui::Widget *ui;QTimer *myTimer;//声明变量MyThread *thread;//线程对象
};
#endif // WIDGET_H
widget.cpp 主窗口主文件
#include "widget.h"
#include "ui_widget.h"
#include <QThread>
#include <QDebug>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);myTimer=new QTimer(this);//只要定时器启动,自动触发timeout()connect(myTimer,&QTimer::timeout,this,&Widget::dealTimeout);//分配空间thread = new MyThread(this);connect(thread,&MyThread::isDone,this,&Widget::dealDone);//当按窗口右上角x时,窗口触发destroyed()信号connect(this,&Widget::destroyed,this,&Widget::stopThread);
}
void Widget::stopThread()
{//停止线程thread->quit();//等待线程处理完手中工作thread->wait();
}void Widget::dealDone()
{qDebug()<<"it is over";myTimer->stop();
}
void Widget::dealTimeout()
{static int i =0;i++;//设置LCD的值ui->lcdNumber->display(i);
}Widget::~Widget()
{delete ui;
}void Widget::on_pushButton_clicked()
{//如果定时器没有工作if(myTimer->isActive()==false){myTimer->start(100);}//启动线程,处理数据thread->start();
}
现象
5秒停止,打印"it is over"
线程新的用法
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);signals:void mySignal();private:bool isStop;};#endif // MYTHREAD_H
mythread.cpp文件
#include "mythread.h"
#include <QThread>
#include <QDebug>
#include <QMessageBox>MyThread::MyThread(QObject *parent) : QObject(parent)
{isStop=false;
}void MyThread::myTimeout()
{while(isStop==false){QThread::sleep(1);emit mySignal();//QMessageBox::aboutQt(NULL);qDebug()<<"子线程号:"<<QThread::currentThread();if(true==isStop){break;}}}void MyThread::setFlag(bool flag)
{isStop=flag;
}
widget.h头文件
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include "mythread.h"
#include <QThread>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();void dealSignal();void dealClose();
signals:void startThread();//启动子线程的信号private slots:void on_ButtonStart_clicked();void on_ButtonStop_clicked();private:Ui::Widget *ui;MyThread *myT;QThread *thread;};
#endif // WIDGET_H
widget.cpp文件
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);//动态分配空间,不能指定父对象//指定父对象后,不能movemyT =new MyThread;//创建子线程thread =new QThread(this);//把自定义的线程加入到子线程中myT->moveToThread(thread);connect(myT,&MyThread::mySignal,this,&Widget::dealSignal);qDebug()<<"主线程号:"<<QThread::currentThread();connect(this,&Widget::startThread,myT,&MyThread::myTimeout);connect(this,&Widget::destroyed,this,&Widget::dealClose);//线程处理函数内部,不允许操作图形界面//connect()第五个参数的作用,连接方式:默认,队列,直接//多线程才有意义,//默认的时候//如果是多线程,默认使用队列//如果是单线程,默认使用直接方式//队列:槽函数所在线程和接收者一样//直接:槽函数所在线程和发送者一样
}Widget::~Widget()
{delete ui;
}void Widget::dealClose()
{on_ButtonStop_clicked();delete myT;
}void Widget::dealSignal()
{static int i=0;i++;ui->lcdNumber->display(i);}
void Widget::on_ButtonStart_clicked()
{if(thread->isRunning()==true){return;}//启动线程,但是没有启动线程处理函数thread->start();myT->setFlag(false);//不能直接调用线程处理函数//直接调用会导致线程处理函数和主线程是在同一个线程//myT->myTimeout();//只能通过 signal-slot方式调用emit startThread();
}void Widget::on_ButtonStop_clicked()
{if(thread->isRunning()==false){return;}myT->setFlag(true);thread->quit();//线程手头工作处理不完thread->wait();
}
现象
在黑马的视频里面说,线程内部不能处理图形,但是我这里是运行出来的了,QMessageBox,但是后面又出问题,闪退了
线程画图
流程
mythread.h头文件
#ifndef MYTHREAD_H
#define MYTHREAD_H#include <QImage>
#include <QObject>class MyThread : public QObject
{Q_OBJECT
public:explicit MyThread(QObject *parent = nullptr);//线程处理函数void drawImage();
signals:void updateImage(QImage temp);};#endif // MYTHREAD_H
mythread.cpp文件
#include "mythread.h"
#include<QPainter>
#include <QPen>
#include <QBrush>
#include <QThread>
MyThread::MyThread(QObject *parent) : QObject(parent)
{}
void MyThread::drawImage()
{//定义QImage绘图设备QImage image(500,500,QImage::Format_ARGB32);//定义画家,指定绘图设备QPainter p(&image);//定义画笔对象QPen pen;pen.setWidth(5);//设置宽度//把画笔交给画家p.setPen(pen);//定义画刷QBrush brush;brush.setStyle(Qt::SolidPattern);//设置样式brush.setColor(Qt::red);//设定颜色//把画刷交给画家p.setBrush(brush);//定义5个点QPoint a[] ={QPoint(qrand()%500,qrand()%500),QPoint(qrand()%500,qrand()%500),QPoint(qrand()%500,qrand()%500),QPoint(qrand()%500,qrand()%500),QPoint(qrand()%500,qrand()%500)};p.drawPolygon(a,5);//通过信号发送图片emit updateImage(image);}
widget.h头文件
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include "mythread.h"
#include <QThread>
#include <QImage>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();//重写绘图事件void paintEvent(QPaintEvent *);void getImage(QImage temp);void dealClose();//窗口关闭槽函数private:Ui::Widget *ui;QImage image;MyThread *myT;//自定义线程对象QThread *thread;
};
#endif // WIDGET_H
widget.cpp文件
#include "widget.h"
#include "ui_widget.h"
#include <QPainter>
#include <QThread>
#include <QPushButton>
#include <QImage>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);//自定义类对象,分配空间,不可以指定父对象myT=new MyThread;//创建子线程thread=new QThread(this);//把自定义模块添加到子线程myT->moveToThread(thread);//启动子线程,但是并没有启动线程处理函数thread->start();//线程处理函数,必须通过signal -solt调用connect(ui->pushButton,&QPushButton::pressed,myT,&MyThread::drawImage);connect(myT,&MyThread::updateImage,this,&Widget::getImage);connect(this,&Widget::destroyed,this,&Widget::dealClose);}Widget::~Widget()
{delete ui;
}
void Widget::dealClose()
{//退出子线程thread->quit();//回收资源thread->wait();delete myT;}
void Widget::getImage(QImage temp)
{image=temp;update(); //更新窗口,间接调用painEvent()}void Widget::paintEvent(QPaintEvent *)
{QPainter p(this);//创建画家,指定绘图设备为窗口p.drawImage(50,50,image);
}