Qt绘制仪表————附带详细说明和代码示例
文章目录
- 1 效果
- 2 原理
- 3 编码实践
- 3.1 创建仪表属性类
- 3.2 设置类属性
- 3.3 绘制图案
- 3.3.1 设置反走样
- 3.3.2 绘制背景
- 3.3.3 重新定义坐标原点
- 3.3.4 绘制圆环
- 3.3.5 绘制刻度线
- 3.3.6 绘制刻度线上的描述值
- 3.3.7 绘制指针
- 3.3.8 绘制指针数值和单位
- 3.3.9 控制指针变化
- 扩展
- 福利
- 参考
1 效果
下面仪表模拟的是转速表和速度表,转速表中有怠速转速,降功转速的逻辑。

下面是模拟双针仪表的效果:

2 原理
1,重写paintEvent进行仪表绘制,使用QPropertyAnimation进行动画绘制;
2,进行属性动画绘制时,需要使用Q_PROPERTY宏用于声明类的属性;
3 编码实践
下面代码位调用方法,接口的具体实现在后文中有详细描述。
发射的信号:
//发送发动机转速void sendEngineSpeed(double);//发送大机速度值void sendTrainSpeedNum(short);
创建仪表类并设置参数:
//发动机转速表DashBoardWidget3 *dashBoardWidget5 = new DashBoardWidget3(this);dashBoardWidget5->setScaleMajor(6);//6个大区间dashBoardWidget5->setScaleMinor(5);//每个区间5个小格dashBoardWidget5->setUnit("");dashBoardWidget5->setText("RPMx100");dashBoardWidget5->setmax(30);dashBoardWidget5->setUnitDrawInterval(1);//每隔一个大区间画一个刻度线描述值dashBoardWidget5->setGeometry(750, 20, 300, 300);connect(this, &MainInterface::sendEngineSpeed,dashBoardWidget5, &DashBoardWidget3::valueChanged);//汽车速度表DashBoardWidget3 *dashBoardWidget6 = new DashBoardWidget3(this);dashBoardWidget6->setScaleMajor(12);//大区间dashBoardWidget6->setScaleMinor(2);//每个区间的小值dashBoardWidget6->setUnit("");dashBoardWidget6->setText("km/h");dashBoardWidget6->setmax(120);dashBoardWidget6->setUnitDrawInterval(2);// dashBoardWidget->move(600, 20);dashBoardWidget6->setGeometry(750, 300, 300, 300);connect(this, &MainInterface::sendTrainSpeedNum,dashBoardWidget6, &DashBoardWidget3::valueChanged);
3.1 创建仪表属性类
struct DashBoardWidgetPrivate{//刻度值的最大值和最小值int maxValue = 100;int minValue = 0;//刻度值角度double startAngle = -50;double endAngle = 230;double value = minValue;//大区间,最小区间int scaleMajor = 10;int scaleMinor = 5;//单位和描述文字QString unit = "";QString text = "";//仪表颜色QColor arcColor = QColor(56, 61, 74);//QColor(0, 128, 255);//刻度颜色QColor scaleColor = QColor(71, 186, 252);//QColor(4, 168, 173);//指针颜色QColor pointerColor = QColor(255, 0, 0);//文件颜色QColor textColor = QColor(144, 133, 116);//背景颜色QColor backgroundColor = Qt::transparent;//仪表指针1:属性动画QPropertyAnimation *animation;};
3.2 设置类属性
Q_PROPERTY(double value READ value WRITE setValue)Q_PROPERTY(double min READ min WRITE setMin)Q_PROPERTY(double max READ max WRITE setmax)Q_PROPERTY(double startAngle READ startAngle WRITE setStartAngle)Q_PROPERTY(double endAngle READ endAngle WRITE setEndAngle)Q_PROPERTY(int scaleMajor READ scaleMajor WRITE setScaleMajor)Q_PROPERTY(int scaleMinor READ scaleMinor WRITE setScaleMinor)Q_PROPERTY(QString unit READ unit WRITE setUnit)Q_PROPERTY(QString text READ text WRITE setText)Q_PROPERTY(QColor arcColor READ arcColor WRITE setArcColor)Q_PROPERTY(QColor scaleColor READ scaleColor WRITE setScaleColor)Q_PROPERTY(QColor pointerColor READ pointerColor WRITE setPointerColor)Q_PROPERTY(QColor textColor READ textColor WRITE setTextColor)Q_PROPERTY(QColor backgroundColor READ backgroundColor WRITE setBackgroundColor)
创建对应的函数:
QSize sizeHint() const override;QSize minimumSizeHint() const override;double value() const;void setValue(const double value);void setMin(const double min);double min() const;void setmax(const double max);double max() const;void setStartAngle(const double startAngle);double startAngle() const;void setEndAngle(const double endAngle);double endAngle() const;void setScaleMajor(const int scale);int scaleMajor() const;void setScaleMinor(const int scale);int scaleMinor() const;void setUnit(const QString &unit);//设置单位QString unit() const;void setText(const QString &text);//设置文字QString text() const;void setArcColor(const QColor &color);QColor arcColor() const;void setScaleColor(const QColor &color);QColor scaleColor() const;void setPointerColor(const QColor &color);QColor pointerColor() const;void setTextColor(const QColor &color);QColor textColor() const;void setBackgroundColor(const QColor &color);QColor backgroundColor() const;
3.3 绘制图案
在类绘制事件中,添加各种绘制信息:
void DashBoardWidget3::paintEvent(QPaintEvent *event){QWidget::paintEvent(event);QPainter painter(this);//....
}
3.3.1 设置反走样
//反走样是图形学中的重要概念,用以防止通常所说的“锯齿”现象的出现。很多系统的绘图 API 里面都内置了有关反走样的算法,不过由于性能问题,默认一般是关闭的painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
3.3.2 绘制背景
// 背景if (d->backgroundColor != Qt::transparent) {painter.setPen(Qt::NoPen);painter.fillRect(rect(), d->backgroundColor);}
3.3.3 重新定义坐标原点
// 平移中心painter.translate(width() / 2, height() / 2);
调整之前:

调整之后:

3.3.4 绘制圆环
// 圆环drawArc(&painter);
实现函数:
void DashBoardWidget3::drawArc(QPainter *painter)
{double min = qMin(width(), height());double arcWidth = min / 15.0;double radius = min / 3 - arcWidth;QRectF rect = QRectF(-radius, -radius, radius * 2, radius * 2);QPen pen;pen.setWidthF(arcWidth);pen.setCapStyle(Qt::FlatCap);// 圆弧背景double angle = d->endAngle - d->startAngle;pen.setColor(d->arcColor);painter->setPen(pen);painter->drawArc(rect, d->startAngle * 16, angle * 16);
}
绘制效果如下:

3.3.5 绘制刻度线
// 刻度线drawScale(&painter);
实现函数:
void DashBoardWidget3::drawScale(QPainter *painter)
{painter->save();painter->rotate(270 - d->endAngle);int steps = (d->scaleMajor * d->scaleMinor);//区间*每个区间的小刻度double angleStep = (d->endAngle - d->startAngle) / steps;double min = qMin(width(), height());double radius = min / 3;QPen pen(d->scaleColor);pen.setCapStyle(Qt::RoundCap);for (int i = 0; i <= steps; i++) {if (i % d->scaleMinor == 0) {//画大刻度pen.setWidthF(1.5);painter->setPen(pen);painter->drawLine(0, radius - 8, 0, radius + 5);//画刻度线长度}else{//画小刻度pen.setWidthF(0.5);painter->setPen(pen);painter->drawLine(0, radius - 8, 0, radius - 3);}painter->rotate(angleStep);}painter->restore();
}
效果如下:

3.3.6 绘制刻度线上的描述值
// 刻度线上的描述值drawScaleNum(&painter);
实现函数:
//画刻度线上的说明值
void DashBoardWidget3::drawScaleNum(QPainter *painter)
{painter->save();painter->setPen(d->scaleColor);double min = qMin(width(), height());double radius = min / 2.4;//半径QFont font("Microsoft YaHei", min / 25);painter->setFont(font);double startRad = d->endAngle * (M_PI / 180);//qDebug()<<"startRad:"<<startRad;double deltaRad = (d->endAngle - d->startAngle) * (M_PI / 180) / d->scaleMajor;QFontMetrics fontMetrics(font);if(m_unitDrawInterval > d->scaleMajor){m_unitDrawInterval = d->scaleMajor;}for (int i = 0; i <= d->scaleMajor; i += m_unitDrawInterval) {//每个大区间都要画刻度值double sina = qSin(startRad - i * deltaRad);double cosa = qCos(startRad - i * deltaRad);double value = 1.0 * i * ((d->maxValue - d->minValue) / d->scaleMajor) + d->minValue;// 1.0 * 1 *((1200 -0)/10) + 0// qDebug()<<"d->maxValue:"<<d->maxValue;//qDebug()<<"d->minValue:"<<d->minValue;//qDebug()<<"value:"<<value;QString strValue = QString("%1").arg(value);double textWidth = fontMetrics.horizontalAdvance(strValue);double textHeight = fontMetrics.height();int x = radius * cosa - textWidth / 2;int y = -radius * sina + textHeight / 4;painter->drawText(x, y, strValue);}painter->restore();
}
效果如下:

3.3.7 绘制指针
// 指示器(指针)drawPointer(&painter);
实现函数:
//画指针
void DashBoardWidget3::drawPointer(QPainter *painter)
{painter->save();painter->setPen(Qt::NoPen);painter->setBrush(d->pointerColor);//设置画笔颜色double radius = qMin(width(), height()) / 3.0;QPolygonF pts;pts << QPointF(-5, 0) << QPointF(0, -8)<< QPointF(5, 0) << QPointF(0, radius);painter->rotate(270 - d->endAngle);double degRotate = (d->endAngle - d->startAngle) / (d->maxValue - d->minValue) * (d->value - d->minValue);painter->rotate(degRotate);painter->drawConvexPolygon(pts);painter->restore();
}
效果如下:

3.3.8 绘制指针数值和单位
// 显示指针数值和单位drawValue(&painter);
实现函数:
//画数值和单位
void DashBoardWidget3::drawValue(QPainter *painter)
{painter->save();painter->setPen(d->textColor);double min = qMin(width(), height());double radius = min / 2.0 - min / 4.8;QFont font("Microsoft YaHei", min / 25);painter->setFont(font);//绘制指针数值和单位QString strValue = QString("%1 %2").arg(d->value).arg(d->unit);QRectF valueRect(-radius, radius / 2.5, radius * 2, radius / 3.5);QColor pointerColor = QColor(0, 0, 0);painter->setBrush(pointerColor);//设置颜色painter->setPen(QPen(QColor(0, 0, 0)));painter->drawText(valueRect, Qt::AlignCenter, strValue);//绘制描述文字QRectF text2Rect(-radius, radius / 1.5, radius * 2, radius / 2.5);painter->setPen(QPen(QColor(255, 0, 0)));//设置画笔颜色painter->setBrush(d->textColor);//设置画笔颜色font.setPixelSize(12);painter->setFont(font);painter->drawText(text2Rect, Qt::AlignCenter, d->text);painter->restore();
}
实现效果:

3.3.9 控制指针变化
signals:void valueChanged(const double value);DashBoardWidget3::DashBoardWidget3(QWidget *parent): QWidget(parent), d(new DashBoardWidgetPrivate)
{d->animation = new QPropertyAnimation(this, "value", this);setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);connect(this, &DashBoardWidget3::valueChanged,this, &DashBoardWidget3::onStartAnimation);}
实现函数:
//仪表指针变动的动画
void DashBoardWidget3::onStartAnimation(double value)
{if(value < d->minValue|| value > d->maxValue|| value == d->value){}else{double start = d->value;double end = value;d->animation->setStartValue(start);d->animation->setEndValue(end);d->animation->start();}
}
扩展
可以思考以下,下面的效果如何实现?

福利
完整的项目代码
欢迎各位start
参考
Qt自定义控件之仪表盘的完整实现
相关文章:
Qt绘制仪表————附带详细说明和代码示例
文章目录 1 效果2 原理3 编码实践3.1 创建仪表属性类3.2 设置类属性3.3 绘制图案3.3.1 设置反走样3.3.2 绘制背景3.3.3 重新定义坐标原点3.3.4 绘制圆环3.3.5 绘制刻度线3.3.6 绘制刻度线上的描述值3.3.7 绘制指针3.3.8 绘制指针数值和单位3.3.9 控制指针变化 扩展福利参考 1 效…...
百度地图JavaScript API核心功能指引
百度地图JavaScript API是一套由JavaScript语言编写的应用程序接口,它能够帮助您在网站中构建功能丰富、交互性强的地图应用,包含了构建地图基本功能的各种接口,提供了诸如本地搜索、路线规划等数据服务。百度地图JavaScript API支持HTTP和HT…...
mp4影像和m4a音频无损合成视频方法
第一步:复制高清视频地址 url 第二步:打开网址粘贴复制的视频url视频下载 第三步:下载-影像.mp4和-音频.m4a 第四步:合并视频; 使用ffmpeg进行无损合成(如果没有安装ffmpeg请自行下载安装下载 FFmpeg (p2hp.com)&…...
Ubuntu下将Julia嵌入Jupyter内核
一.安装 Julia 如果 Julia 尚未安装: 打开终端,下载最新的 Julia 安装包: wget https://julialang-s3.julialang.org/bin/linux/x64/1.9/julia-1.9.3-linux-x86_64.tar.gz 解压并移动到 /opt: tar -xvzf julia-1.9.3-linux-x86_…...
openGauss开源数据库实战二十五
文章目录 任务二十五 openGauss 数据库的物理备份与恢复任务目标实施步骤一、为进行物理备份做准备1.确保数据库工作在归档模式2.创建保存数据库物理备份的目录3.创建保存归档日志备份的目录 二、进行openGauss数据库的物理备份1.备份数据库2.切换WAL3.备份归档日志 三、openGa…...
[C/C++] List相关操作
List相关操作 1 链表二分 目标: (1)对于偶数节点,正好对半分; (2)对于奇数节点,前 后 1 (3)断开链表,方便后期合并 // 使用快慢指针完成中点…...
继电器控制与C++编程:实现安全开关控制的技术分享
在现代生活中,继电器作为一种重要的电气控制元件,在电气设备的安全控制中起到了至关重要的作用。通过低电流控制高电流,继电器能够有效地隔离控制电路与被控设备,从而保障使用者的安全。本项目将介绍如何通过树莓派Pico与继电器模块结合,使用C++编程实现继电器的控制。 一…...
题解 - 找子序列(2024.12上海月赛丙组T4)
题目描述 Dave 有一个长度为 n 的非负整数序列 a1-n, 和一个非负整数 m 。 他希望知道是否有一个 a 的非空子序列,使得子序列中所有元素的按位与(bitwise AND)结果为 m。 换言之,他想知道是否存在一个下标序列 i1-k(k ≥ 1),满足 1 ≤ i1 < i2 < …...
在centos 7.9上面安装mingw交叉编译工具
1.说明 为了在centos上面编译windows的程序,需要安装mingw工具,mingw工具是可以编译windows程序的一些工具链,使用方式和linux一致 2.下载脚本 使用脚本方式编译,github的脚本位置:https://github.com/Zeranoe/ming…...
ubuntu wine mobaxterm找不到串口和解决方案
安装好 打开MobaXterm时发现,没有可供选择的串口 我们再检查wine设备映射 ls -la ~/.wine/dosdevices/ 串口是存在的,我们再来一番神操作,并没有回滚操作,不知是否是必要修改 打开 注册表,在HKEY_LOCAL_MACHINE中的…...
如何编译安装系统settings设置应用(5.0.0-Release)
本文介绍如何在OpenHarmony 5.0.0 r版本中修改系统设置应用,并且编译安装到开发板上 开发环境 1.dayu200开发板 2.OpenHarmony 5.0.0r 固件 3.API12 full sdk (如果安装full sdk过程中出现报错hvigor ERROR: Cannot find module typescript,请参考 h…...
<项目代码>YOLOv8 车牌识别<目标检测>
项目代码下载链接 <项目代码>YOLOv8 车牌识别<目标检测>https://download.csdn.net/download/qq_53332949/90121387YOLOv8是一种单阶段(one-stage)检测算法,它将目标检测问题转化为一个回归问题…...
协同办公软件新升级:细节优化,让办公更简单
细节决定成败,企业酷信协同办公系统通过贴近客户实际需求的一系列改进和创新,在技术架构、系统结构、管理理念和使用性能上,都达到了国内先进水平,同时具备独特的优势。让我们看看企业酷信是如何通过这些细节提升,为企…...
【原创学习笔记】西门子1200 PLC实现变频器控制
一、实现的功能及应用的场合 通过PLC的不同指令,发送指令控制电机的启停和速度大小 二、硬件配置 1、西门子1214 PLC 2.TIA V16 3.SINAMICS G120C 三、实现功能步骤 1.添加设备G120C PN-调整以太网地址 根据实际情况选择有无滤波器,电机参数…...
SQL server学习02-使用T-SQL创建数据库
目录 一, 使用T-SQL创建数据库 1,数据库的存储结构 2,创建数据库的语法结构 1)使用T-SQL创建学生成绩管理数据库 二,使用T-SQL修改数据库 1,修改数据库的语法结构 1)修改学生成绩管理数…...
2024153读书笔记|《春烂漫:新平摄影作品选》——跳绳酷似人生路,起落平常,进退平常,莫惧征途万里长
2024153读书笔记|《春烂漫:新平摄影作品选》——跳绳酷似人生路,起落平常,进退平常,莫惧征途万里长 《春烂漫:新平摄影作品选》作者新平,2019.12.25年读完的小书,当时就觉得挺不错,今…...
MySQL有哪些高可用方案?
大家好,我是锋哥。今天分享关于【MySQL有哪些高可用方案?】面试题。希望对大家有帮助; MySQL有哪些高可用方案? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 MySQL 高可用方案旨在确保数据库系统的高可靠性、低宕机时间、以及在硬件故障…...
前台进程是什么
前台进程是什么 前台进程的定义 前台进程是指在操作系统中,与用户当前正在交互的进程。这些进程通常拥有最高的优先级,因为它们直接影响用户体验,是用户正在关注或者正在使用的应用程序对应的进程。例如,当你在手机上打开一个游戏…...
Redis学习笔记之——学习计划
Redis——Remote Dictionary Server,开源、基于内存、速度快、key-value... Redis做为一个高性能的键值存储系统,广泛应用于缓存、会话存储、分布式锁以及其他需要快速访问的数据场景中。熟悉掌握redis,似乎已成为广大码农们必备的一项技能。…...
npm : 无法加载文件 D:\nodejs\npm.ps1
问题描述 npm run serve 启动一个Vue项目,报错如下: npm : 无法加载文件 D:\nodejs\npm.ps1,因为在此系统上禁止运行脚本。有关详细信息,请参阅 https:/go.microsoft.com/fwlink/? LinkID135170 中的 about_Execution_Policies。…...
Flask RESTful 示例
目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题: 下面创建一个简单的Flask RESTful API示例。首先,我们需要创建环境,安装必要的依赖,然后…...
简易版抽奖活动的设计技术方案
1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...
AtCoder 第409场初级竞赛 A~E题解
A Conflict 【题目链接】 原题链接:A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串,只有在同时为 o 时输出 Yes 并结束程序,否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...
汽车生产虚拟实训中的技能提升与生产优化
在制造业蓬勃发展的大背景下,虚拟教学实训宛如一颗璀璨的新星,正发挥着不可或缺且日益凸显的关键作用,源源不断地为企业的稳健前行与创新发展注入磅礴强大的动力。就以汽车制造企业这一极具代表性的行业主体为例,汽车生产线上各类…...
【磁盘】每天掌握一个Linux命令 - iostat
目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat(I/O Statistics)是Linux系统下用于监视系统输入输出设备和CPU使…...
【配置 YOLOX 用于按目录分类的图片数据集】
现在的图标点选越来越多,如何一步解决,采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集(每个目录代表一个类别,目录下是该类别的所有图片),你需要进行以下配置步骤&#x…...
【JavaWeb】Docker项目部署
引言 之前学习了Linux操作系统的常见命令,在Linux上安装软件,以及如何在Linux上部署一个单体项目,大多数同学都会有相同的感受,那就是麻烦。 核心体现在三点: 命令太多了,记不住 软件安装包名字复杂&…...
React---day11
14.4 react-redux第三方库 提供connect、thunk之类的函数 以获取一个banner数据为例子 store: 我们在使用异步的时候理应是要使用中间件的,但是configureStore 已经自动集成了 redux-thunk,注意action里面要返回函数 import { configureS…...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...
Scrapy-Redis分布式爬虫架构的可扩展性与容错性增强:基于微服务与容器化的解决方案
在大数据时代,海量数据的采集与处理成为企业和研究机构获取信息的关键环节。Scrapy-Redis作为一种经典的分布式爬虫架构,在处理大规模数据抓取任务时展现出强大的能力。然而,随着业务规模的不断扩大和数据抓取需求的日益复杂,传统…...
