【Qt开发】建立自己的Qt基本类、函数库封装 包括图表、多线程、串口等

本文主要是介绍【Qt开发】建立自己的Qt基本类、函数库封装 包括图表、多线程、串口等,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

【Qt开发】建立自己的Qt基本类、函数库 包括图表、多线程、串口等

文章目录

  • 前言
  • QtCharts绘图
  • 继承QObject的QThread多线程
  • QSerialPort串口配置、发送、接收回调函数
  • 附录:C语言到C++的入门知识点(主要适用于C语言精通到Qt的C++开发入门)
    • C语言与C++的不同
    • C++中写C语言代码
    • C语言到C++的知识点
    • Qt开发中需要了解的C++基础知识
      • namespace
      • 输入输出
      • 字符串类型
      • class类
        • 构造函数和析构函数(解析函数)
        • 类的继承

前言

为了使开发更方便 对使用到的模块进行了总结 最终封装成了一个类、函数库
使用typedef、class类、回调函数等来建立 方便打包和开发

开源地址:
gitee地址

QtCharts绘图

【Qt开发】QtCharts图表 在ui上添加QChartView控件并进行绘图配置
可以实现一键配置

#ifndef MY_QT_DEF_H
#define MY_QT_DEF_H
#include <QValueAxis>
#include <QList>
#include <QSplineSeries>
#include <QString>
#include <QChart>
#include <QChartView>
QT_CHARTS_USE_NAMESPACEtypedef struct
{float min;float max;QString tittle;QString format;Qt::Alignment alignment;QValueAxis *axis;
}MY_QChartView_Float_Axis_Struct;//splineSeries曲线实例化(折线用QLineSeries)
typedef struct
{int maxSize;QList<float> data;QString tittle;MY_QChartView_Float_Axis_Struct X;MY_QChartView_Float_Axis_Struct Y;QPainter::RenderHint renderHint;//上面是必配置的参数 下面是指针类型QSplineSeries *splineSeries;QChart *chart;QChartView *chartView;
}MY_QChartView_Float_Struct;void Init_MY_QChartView_Float_Axis_Struct(MY_QChartView_Float_Axis_Struct *Stu,QChart *chart);
void Init_MY_QChartView_Float_Struct(MY_QChartView_Float_Struct *Stu);
void Add_MY_QChartView_Float_Value(MY_QChartView_Float_Struct *Stu,float value);#endif // MY_QT_DEF_H
#include "MY_QT_DEF.h"void Init_MY_QChartView_Float_Axis_Struct(MY_QChartView_Float_Axis_Struct *Stu,QChart *chart)
{Stu->axis->setLabelFormat(Stu->format);Stu->axis->setTitleText(Stu->tittle);chart->addAxis(Stu->axis, Stu->alignment);Stu->axis->setRange(Stu->min,Stu->max);
}void Init_MY_QChartView_Float_Struct(MY_QChartView_Float_Struct *Stu)
{Stu->chart=new QChart();Stu->splineSeries = new QSplineSeries();Stu->X.axis=new QValueAxis();Stu->Y.axis=new QValueAxis();Stu->chart->legend()->hide();Stu->chart->setTitle(Stu->tittle);Stu->chart->addSeries(Stu->splineSeries);Init_MY_QChartView_Float_Axis_Struct(&Stu->X,Stu->chart);Init_MY_QChartView_Float_Axis_Struct(&Stu->Y,Stu->chart);Stu->splineSeries->attachAxis(Stu->X.axis);Stu->splineSeries->attachAxis(Stu->Y.axis);Stu->chartView->setChart(Stu->chart);Stu->chartView->setRenderHint(Stu->renderHint);
}//添加数据自动移动函数
void Add_MY_QChartView_Float_Value(MY_QChartView_Float_Struct *Stu,float value)
{Stu->data.append(value);while (Stu->data.size() > Stu->maxSize){Stu->data.removeFirst();}Stu->splineSeries->clear();float xSpace = (Stu->X.max-Stu->X.min) / (Stu->maxSize - 1);for (int i = 0; i < Stu->data.size(); ++i){Stu->splineSeries->append(xSpace * i, Stu->data.at(i));}
}

继承QObject的QThread多线程

采用moveToThread方法执行多线程
对整体进行了封装
可以自我调用
可以通过注册回调函数来进行不同的工作
【Qt开发】多线程QThread(通过QObject::moveToThread)和QMutex互斥锁的配置和多线程类的封装及回调函数

//QObject的多线程示例
class MY_Thread_Worker;
class MY_Thread_Worker : public QObject
{Q_OBJECT
private:QMutex lock;bool isCanRun;bool isCanStart;MY_QT_CALLBACK pfCallback;
public slots:void Judg_doWork(void){this->isCanRun=true;//执行while(this->isCanRun){QMutexLocker locker(&this->lock);pfCallback(this,0,NULL);}isCanStart=true;}signals:void startWork(void);
public:void * pArg;QThread *workerThread;void stopWork(bool Wait_Flag){this->isCanRun = false;if(Wait_Flag){QMutexLocker locker(&this->lock);}}bool startThread(void){if(!isCanRun && isCanStart){isCanStart=false;workerThread->start();emit this->startWork();return true;}return false;}bool stopThread(bool Wait_Flag){if(workerThread->isRunning()){stopWork(Wait_Flag);return true;}return false;}void closeThread(void){stopThread(false);this->workerThread->quit();}MY_Thread_Worker(MY_QT_CALLBACK const pfunc,QThread * worker_Thread = nullptr){pfCallback=pfunc;pArg=nullptr;if(!worker_Thread){this->workerThread = new QThread;}else{this->workerThread = worker_Thread;}this->moveToThread(workerThread);this->stopWork(false);isCanStart=true;connect(workerThread, SIGNAL(finished()),this, SLOT(deleteLater()));connect(workerThread, SIGNAL(finished()), workerThread, SLOT(deleteLater()));connect(this, SIGNAL(startWork()), this, SLOT(Judg_doWork()));// connect(this, SIGNAL(startWork(QString)), worker, SLOT(Judg_doWork(QString)));  主窗口发送函数// connect(worker, SIGNAL(resultReady(QString)),this, SLOT(handleResults(QString)));  主窗口接收函数}~MY_Thread_Worker(){closeThread();}
};

QSerialPort串口配置、发送、接收回调函数

包装的类具有 单线程/多线程 回调函数/虚函数四种配置方案
同样采用回调函数方便配置和修改
【Qt开发】QSerialPort串口配置、发送、接收回调函数 多线程接收的串口类封装

class MY_SerialPort_Thread;
class MY_SerialPort_Thread : public QObject
{Q_OBJECT
private:QMutex lock;bool isCanRun;bool isCanStart;bool Thread_Flag;MY_QT_CALLBACK pfCallback;
public slots:void SerialPort_RX(void){SerialPort_RX_Ready_Callback(this);}void Callback_SerialPort_RX(void){pfCallback(this,0,NULL);}void RX_Thread(void){this->isCanRun=true;//执行while(isCanRun){QMutexLocker locker(&this->lock);if(SerialPort.waitForReadyRead(1)){SerialPort_RX_Thread_Callback(this);}}isCanStart=true;}void Callback_RX_Thread(void){this->isCanRun=true;//执行while(isCanRun){QMutexLocker locker(&this->lock);if(SerialPort.waitForReadyRead(1)){pfCallback(this,1,NULL);}}isCanStart=true;}signals:void Start_RX_Thread(void);public:QSerialPort SerialPort;QList<QString> SerialPort_List;QString SerialPort_Name;uint32_t BaudRate;uint8_t DataBits;uint8_t StopBits;QSerialPort::Parity Parity;QSerialPort::FlowControl FlowControl;bool Open_Flag;uint8_t RX_Data;uint8_t *RX_Buf;uint32_t RX_Buf_Size;uint32_t RX_Flag;QThread workerThread;void Stop_Port(uint8_t TX_RX_All){switch(TX_RX_All){case 0:SerialPort.clear(QSerialPort::Output);break;case 1:SerialPort.clear(QSerialPort::Input);break;default:SerialPort.clear();SerialPort.flush();break;}}void Scan_SerialPort(void){SerialPort_List.clear();foreach (const QSerialPortInfo &info,QSerialPortInfo::availablePorts()){SerialPort_List.append(info.portName());}}void Clean_RX(void){RX_Flag=0;RX_Data=0;memset(RX_Buf,0,RX_Buf_Size);}void Reset_SerialPort(void){Scan_SerialPort();BaudRate=115200;DataBits=8;StopBits=1;Parity=QSerialPort::NoParity;FlowControl = QSerialPort::NoFlowControl;if(Open_Flag){Stop_Port(2);}Clean_RX();}bool Ctrl_SerialPort(bool OpenNotClose){if(OpenNotClose){SerialPort.setPortName(SerialPort_Name);SerialPort.setBaudRate(BaudRate);SerialPort.setFlowControl(FlowControl);switch(DataBits){case 5:SerialPort.setDataBits(QSerialPort::Data5);break;case 6:SerialPort.setDataBits(QSerialPort::Data6);break;case 7:SerialPort.setDataBits(QSerialPort::Data7);break;case 8:SerialPort.setDataBits(QSerialPort::Data8);break;default:break;}SerialPort.setParity(Parity);switch(StopBits){case 1:SerialPort.setStopBits(QSerialPort::OneStop);break;case 2:SerialPort.setStopBits(QSerialPort::TwoStop);break;case 3:SerialPort.setStopBits(QSerialPort::OneAndHalfStop);break;default:break;}if (!SerialPort.open(QIODevice::ReadWrite)){return false;}Open_Flag=true;if(this->Thread_Flag){startThread();}return true;}stopThread(true);Open_Flag=false;SerialPort.close();        return true;}uint32_t SerialPort_TX_Sequence(uint8_t *buf,uint32_t size){if(Open_Flag){return SerialPort.write((char *)buf,size);}return 0;}uint32_t SerialPort_TX(uint8_t *buf,uint32_t size){if(Open_Flag){SerialPort.clear(QSerialPort::Output);return SerialPort.write((char *)buf,size);}return 0;}virtual void SerialPort_RX_Ready_Callback(MY_SerialPort_Thread *port){Q_UNUSED(port);foreach (const uint8_t i,port->SerialPort.readAll()){port->RX_Data=i;SerialPort_RX_Callback(port);}}virtual void SerialPort_RX_Thread_Callback(MY_SerialPort_Thread *port){Q_UNUSED(port);foreach (const uint8_t i,port->SerialPort.readAll()){port->RX_Data=i;SerialPort_RX_Callback(port);}}virtual void SerialPort_RX_Callback(MY_SerialPort_Thread *port){Q_UNUSED(port);qDebug()<<port->RX_Data;}void stopWork(bool Wait_Flag){this->isCanRun = false;if(Wait_Flag){QMutexLocker locker(&this->lock);}}bool startThread(void){if(!isCanRun && isCanStart){isCanStart=false;workerThread.start();emit this->Start_RX_Thread();return true;}return false;}bool stopThread(bool Wait_Flag){if(workerThread.isRunning()){stopWork(Wait_Flag);return true;}return false;}void closeThread(void){stopThread(false);this->workerThread.quit();}MY_SerialPort_Thread(uint32_t Buf_Size=256,bool ThreadNotNormal=false,MY_QT_CALLBACK const pfunc=nullptr){pfCallback=pfunc;SerialPort_Name="";Open_Flag=false;RX_Buf_Size = Buf_Size;RX_Buf = new uint8_t[RX_Buf_Size];SerialPort.setReadBufferSize(RX_Buf_Size);this->Thread_Flag = ThreadNotNormal;Reset_SerialPort();if(Thread_Flag){this->moveToThread(&workerThread);this->stopWork(false);isCanStart=true;connect(&workerThread, SIGNAL(finished()),this, SLOT(deleteLater()));connect(&workerThread, SIGNAL(finished()), &workerThread, SLOT(deleteLater()));if(pfCallback){connect(this, SIGNAL(Start_RX_Thread()), this, SLOT(Callback_RX_Thread()));}else{connect(this, SIGNAL(Start_RX_Thread()), this, SLOT(RX_Thread()));}}else{            if(pfCallback){connect(&this->SerialPort, SIGNAL(readyRead()),this, SLOT(Callback_SerialPort_RX()));}else{connect(&this->SerialPort, SIGNAL(readyRead()),this, SLOT(SerialPort_RX()));}}}~MY_SerialPort_Thread(){Open_Flag=false;SerialPort.close();delete RX_Buf;closeThread();}
};

附录:C语言到C++的入门知识点(主要适用于C语言精通到Qt的C++开发入门)

C语言与C++的不同

C语言是一门主要是面向工程的语言
C++则是面向对象

C语言中 某些功能实现起来较为繁琐
比如结构体定义:

一般写作:

typedef struct stu_A
{
}A;

也可以写作:

typedef struct 
{
}A;

但 大括号后面的名称是不可省去的

不过 C++的写法就比较简单
除了支持上述写法外

也支持直接声明

typedef struct A
{
}

另外 C++是完全支持C语言库和语法的
不过C++里面的库也有些很方便的高级功能用法 只不过实现起来可能不如C的速度快

再者 C语言与C++的编译流程不一样
C语言没有函数重载 所以给编译器传参就是直接传函数名称
但是C++除了传函数名称外 还会穿函数的参数、类型等等 以实现函数重载

C++中写C语言代码

上文提到 C++可以完全兼容C的写法
但是编译流程也还是不一样
所以如果在编译层面进行C语言代码编译 则通常用以下方法:

extern "C"
{
...
}

表面大括号内的内容用C的方法进行编译

另外 如果还是用C++的编译器 但要实现C语言函数 则需要用到C语言的库

在C语言中 我们一般用如下方法导入库

#include <stdio.h>

此方法同样适用于C++ 但是C++可以更方便的写成去掉.h的方式
比如:

#include <iostream>

在C++中 为了调用C语言的库 可以采用在原库名称前加一个"c"的方式导入
如:

#include <cstdio>

这样就可以使用printf等函数了 甚至比C++的std方法更快

C语言到C++的知识点

在这里插入图片描述

Qt开发中需要了解的C++基础知识

namespace

C++面向对象的特性下诞生的一个名称
表示某个函数、变量在某个集合下 用作namespace
比如 <iostream>库中的关键字cin在std下 则写作std::cin
std就是namespace
::表示某空间下的某某
前面是空间名称 后面是变量、函数名称

using namespace可以告诉编译器以下都用xx名称空间
比如:

using namespace std;
cout<<"a";

如果没有告诉编译器所使用的空间名称 则要写成:

std::cout<<"a";

同样 可以自定义某一段代码属于哪个空间:

namespace xx
{
...
}

输入输出

在C++中 用iostream作为输入输出流的库

#include <iostream>

用cin和cout关键字进行输入和输出
如:

using namespace std;
int a=0;
cin>>a; //输入到acout<<a;  //输出a

类比scanf和printf
同样 还有一个关键字endl表示换行
cout和cin的传参是不固定的
由编译器自行裁定

字符串类型

在C语言中 常用char *表示字符串
但是在C++中 可以直接用string类型
比如:

char * s="456";
string str="123";

由于cout的特性 这两种字符串都可以直接打印
但如果使用C语言中printf的打印方式时 采用%s方式打印字符串 则不能传入string类型

class类

C++的核心就是class
同Python等支持面向对象的语言一样
可以理解成一个支持函数、继承、自动初始化、销毁的结构体
在class类中 有private私有、public公有变量
前者只能内部访问 后者可以外部调用使用
如:

class A
{
public:
int a;
private:
int b;
}

a可以用A.a的方式方位 b则外部无法访问

构造函数和析构函数(解析函数)

构造函数可以理解成对类的初始化 反之析构函数则是退出时进行销毁前的函数
两者需要与类的名称相同 析构函数则在前面加一个~表示非
如:

class A
{
public:
int a;
A();
~A();
private:
int b;
}A::A()
{
...
}A::~A()
{
...
}

构造函数可以定义传参 析构函数则不行

类的继承

如果有两个类A和B 想让A里面包含B 则可以写作继承的写法
继承后 A类的变量可以直接调用B下面的成员
如:

class B
{
int b;
}
class A: public B
{
int a;
}

在定义A后 可以访问到B的成员b 当然 继承也可以私有

这篇关于【Qt开发】建立自己的Qt基本类、函数库封装 包括图表、多线程、串口等的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1101911

相关文章

Qt QCustomPlot库简介(最新推荐)

《QtQCustomPlot库简介(最新推荐)》QCustomPlot是一款基于Qt的高性能C++绘图库,专为二维数据可视化设计,它具有轻量级、实时处理百万级数据和多图层支持等特点,适用于科学计算、... 目录核心特性概览核心组件解析1.绘图核心 (QCustomPlot类)2.数据容器 (QCPDataC

使用Python实现可恢复式多线程下载器

《使用Python实现可恢复式多线程下载器》在数字时代,大文件下载已成为日常操作,本文将手把手教你用Python打造专业级下载器,实现断点续传,多线程加速,速度限制等功能,感兴趣的小伙伴可以了解下... 目录一、智能续传:从崩溃边缘抢救进度二、多线程加速:榨干网络带宽三、速度控制:做网络的好邻居四、终端交互

Go语言数据库编程GORM 的基本使用详解

《Go语言数据库编程GORM的基本使用详解》GORM是Go语言流行的ORM框架,封装database/sql,支持自动迁移、关联、事务等,提供CRUD、条件查询、钩子函数、日志等功能,简化数据库操作... 目录一、安装与初始化1. 安装 GORM 及数据库驱动2. 建立数据库连接二、定义模型结构体三、自动迁

ModelMapper基本使用和常见场景示例详解

《ModelMapper基本使用和常见场景示例详解》ModelMapper是Java对象映射库,支持自动映射、自定义规则、集合转换及高级配置(如匹配策略、转换器),可集成SpringBoot,减少样板... 目录1. 添加依赖2. 基本用法示例:简单对象映射3. 自定义映射规则4. 集合映射5. 高级配置匹

Golang如何对cron进行二次封装实现指定时间执行定时任务

《Golang如何对cron进行二次封装实现指定时间执行定时任务》:本文主要介绍Golang如何对cron进行二次封装实现指定时间执行定时任务问题,具有很好的参考价值,希望对大家有所帮助,如有错误... 目录背景cron库下载代码示例【1】结构体定义【2】定时任务开启【3】使用示例【4】控制台输出总结背景

SpringBoot开发中十大常见陷阱深度解析与避坑指南

《SpringBoot开发中十大常见陷阱深度解析与避坑指南》在SpringBoot的开发过程中,即使是经验丰富的开发者也难免会遇到各种棘手的问题,本文将针对SpringBoot开发中十大常见的“坑... 目录引言一、配置总出错?是不是同时用了.properties和.yml?二、换个位置配置就失效?搞清楚加

Qt如何实现文本编辑器光标高亮技术

《Qt如何实现文本编辑器光标高亮技术》这篇文章主要为大家详细介绍了Qt如何实现文本编辑器光标高亮技术,文中的示例代码讲解详细,具有一定的借鉴价值,有需要的小伙伴可以了解下... 目录实现代码函数作用概述代码详解 + 注释使用 QTextEdit 的高亮技术(重点)总结用到的关键技术点应用场景举例示例优化建议

Qt 设置软件版本信息的实现

《Qt设置软件版本信息的实现》本文介绍了Qt项目中设置版本信息的三种常用方法,包括.pro文件和version.rc配置、CMakeLists.txt与version.h.in结合,具有一定的参考... 目录在运行程序期间设置版本信息可以参考VS在 QT 中设置软件版本信息的几种方法方法一:通过 .pro

Python中对FFmpeg封装开发库FFmpy详解

《Python中对FFmpeg封装开发库FFmpy详解》:本文主要介绍Python中对FFmpeg封装开发库FFmpy,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录一、FFmpy简介与安装1.1 FFmpy概述1.2 安装方法二、FFmpy核心类与方法2.1 FF

基于Python开发Windows屏幕控制工具

《基于Python开发Windows屏幕控制工具》在数字化办公时代,屏幕管理已成为提升工作效率和保护眼睛健康的重要环节,本文将分享一个基于Python和PySide6开发的Windows屏幕控制工具,... 目录概述功能亮点界面展示实现步骤详解1. 环境准备2. 亮度控制模块3. 息屏功能实现4. 息屏时间