Qt学习记录(14)线程

前言:

我的臀部已经翘到可以顶起一屁股债了

为什么要使用线程

什么时候用线程

复杂的数据处理

头文件.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QTimer>//定时器头文件

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    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 线程头文件

cs 复制代码
#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 线程主文件

cs 复制代码
#include "mythread.h"

MyThread::MyThread(QObject *parent) : QThread(parent)
{

}

void MyThread::run()
{
    //很复杂的数据处理
    //需要耗时5s
    sleep(5);

    emit isDone();
}

widget.h主窗口头文件

添加了线程头文件,线程槽函数,线程停止函数,线程对象

cpp 复制代码
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QTimer>//定时器头文件
#include "mythread.h"//线程头文件

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    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 主窗口主文件

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_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    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);

    //动态分配空间,不能指定父对象
    //指定父对象后,不能move
    myT =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_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    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);
}

现象

相关推荐
流星白龙1 分钟前
【C++习题】10.反转字符串中的单词 lll
开发语言·c++
尘浮生8 分钟前
Java项目实战II基于微信小程序的校运会管理系统(开发文档+数据库+源码)
java·开发语言·数据库·微信小程序·小程序·maven·intellij-idea
MessiGo9 分钟前
Python 爬虫 (1)基础 | 基础操作
开发语言·python
Tech Synapse15 分钟前
Java根据前端返回的字段名进行查询数据的方法
java·开发语言·后端
Mephisto.java18 分钟前
【大数据学习 | Spark-Core】Spark提交及运行流程
大数据·学习·spark
乌啼霜满天24923 分钟前
JDBC编程---Java
java·开发语言·sql
色空大师36 分钟前
23种设计模式
java·开发语言·设计模式
PandaCave43 分钟前
vue工程运行、构建、引用环境参数学习记录
javascript·vue.js·学习
yuwinter1 小时前
鸿蒙HarmonyOS学习笔记(2)
笔记·学习·harmonyos
Bruce小鬼1 小时前
QT文件基本操作
开发语言·qt