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

现象

相关推荐
anlog5 分钟前
C#在自定义事件里传递数据
开发语言·c#·自定义事件
奶香臭豆腐18 分钟前
C++ —— 模板类具体化
开发语言·c++·学习
晚夜微雨问海棠呀26 分钟前
长沙景区数据分析项目实现
开发语言·python·信息可视化
graceyun27 分钟前
C语言初阶习题【9】数9的个数
c语言·开发语言
波音彬要多做1 小时前
41 stack类与queue类
开发语言·数据结构·c++·学习·算法
Swift社区1 小时前
Excel 列名称转换问题 Swift 解答
开发语言·excel·swift
一道微光1 小时前
Mac的M2芯片运行lightgbm报错,其他python包可用,x86_x64架构运行
开发语言·python·macos
矛取矛求1 小时前
QT的前景与互联网岗位发展
开发语言·qt
Leventure_轩先生1 小时前
[WASAPI]从Qt MultipleMedia来看WASAPI
开发语言·qt
向宇it2 小时前
【从零开始入门unity游戏开发之——unity篇01】unity6基础入门开篇——游戏引擎是什么、主流的游戏引擎、为什么选择Unity
开发语言·unity·c#·游戏引擎