当前位置: 首页 > news >正文

QT 实现两款自定义的温度计/湿度控件

文章目录

  • 0 引入
  • 1、带有标尺的温度/湿度计控件
    • 1.头文件
    • 2.核心代码
  • 2、竖起来的温度/湿度计控件
    • 1.头文件
    • 2.实现
  • 3、引用


在这里插入图片描述

0 引入

QT原生控件没有实现如仪表盘或者温度计的控件,只好自己实现,文章代码部分参考引用的文章。直接上图

图一 带有标尺的温度计、湿度带有标尺的温度计、湿度
图二 温度计、湿度

在这里插入图片描述
控件最核心的部分:在函数paintEvent绘制部分,如果需要动画效果还需要加一个QPropertyAnimation ,这是最主要的,剩下的细节根据需求增加减少即可。


1、带有标尺的温度/湿度计控件

因为只做数据显示用,所以只需要向控件传数据即可。
主要功能:1、可设置显示范围;
2、显示过程中加了动画效果;
3、背景色和前景色以及刻度尺颜色可变;
4、刻度尺间距可变,控件大小随着QWidget适应;

1.头文件

代码如下(示例):

protected:void paintEvent(QPaintEvent *);void drawBg(QPainter *painter);void drawProgress(QPainter *painter);void drawRulerTop(QPainter *painter);void drawRulerBottom(QPainter *painter);private:QPropertyAnimation *m_valueAnimation;double minValue;                //最小值double maxValue;                //最大值qreal value;                    //当前值int longStep;                   //长线条等分步长int shortStep;                  //短线条等分步长bool rulerTop;                  //刻度线在上面bool isAdd;                     //是否为增加,默认为的增加QColor bgColor;                 //背景颜色QColor lineColor;               //线条颜色QColor progressColor;           //进度颜色public:qreal getValue()               const;void setrulerTop(bool istop);   //设定刻度线再上还是在下,默认是在上void setValue(qreal v);void setRange(int minValue, int maxValue);void startAnimation();void updateValue(double value);void setBgColor(const QColor &bgColor);               //设置背景颜色void setLineColor(const QColor &lineColor);           //设置线条颜色void setProgressColor(const QColor &progressColor);   //设置进度颜色

2.核心代码

绘制部分参考引用2代码,感谢刘典武老师的无私开源,有需要的可去做定制。
代码如下:

void HumidityProgress::startAnimation()
{qreal startValue =  value;if(isAdd){m_valueAnimation->setKeyValueAt(0.5, value+0.5);m_valueAnimation->setKeyValueAt(1, value);m_valueAnimation->setStartValue(startValue-0.5);m_valueAnimation->start();}else{m_valueAnimation->setKeyValueAt(0.5, value-0.5);m_valueAnimation->setKeyValueAt(1, value);m_valueAnimation->setStartValue(startValue+0.5);m_valueAnimation->start();}}void HumidityProgress::paintEvent(QPaintEvent *)
{//绘制准备工作,启用反锯齿QPainter painter(this);painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);//按照绘制顺序drawBg(&painter);drawProgress(&painter);if (rulerTop) {drawRulerTop(&painter);} else {drawRulerBottom(&painter);}
}void HumidityProgress::drawBg(QPainter *painter)
{painter->save();painter->setPen(lineColor);painter->setBrush(bgColor);painter->drawRect(rect());painter->restore();
}void HumidityProgress::drawProgress(QPainter *painter)
{painter->save();painter->setPen(Qt::NoPen);painter->setBrush(progressColor);double length = width();double increment = length / (maxValue - minValue);double initX = (value - minValue) * increment;QRect rect(0, 0, initX, height());painter->drawRect(rect);painter->restore();
}void HumidityProgress::drawRulerTop(QPainter *painter)
{painter->save();painter->setPen(lineColor);double initX = 0;//绘制横向标尺上部分底部线double initTopY = 0;QPointF lineTopLeftPot = QPointF(initX, initTopY);QPointF lineTopRightPot = QPointF(width() - initX, initTopY);painter->drawLine(lineTopLeftPot, lineTopRightPot);//绘制上部分及下部分横向标尺刻度double length = width();//计算每一格移动多少double increment = length / (maxValue - minValue);//长线条短线条长度int longLineLen = 15;int shortLineLen = 10;//根据范围值绘制刻度值及刻度值 长线条需要移动10像素 短线条需要移动5像素for (int i = minValue; i <= maxValue; i = i + shortStep) {if (i % longStep == 0) {QPointF topPot = QPointF(initX, initTopY);QPointF bottomPot = QPointF(initX, initTopY + longLineLen);painter->drawLine(topPot, bottomPot);//第一个值和最后一个值不要绘制if (i == minValue || i == maxValue) {initX += increment * shortStep;continue;}QString strValue = QString("%1").arg((double)i, 0, 'f', 0);double textWidth = fontMetrics().width(strValue);double textHeight = fontMetrics().height();QPointF textPot = QPointF(initX - textWidth / 2, initTopY + textHeight + longLineLen);painter->drawText(textPot, strValue);} else {if (i % (longStep / 2) == 0) {shortLineLen = 10;} else {shortLineLen = 6;}QPointF topPot = QPointF(initX, initTopY);QPointF bottomPot = QPointF(initX, initTopY + shortLineLen);painter->drawLine(topPot, bottomPot);}initX += increment * shortStep;}painter->restore();
}

该处使用的url网络请求的数据。


2、竖起来的温度/湿度计控件

因为只做数据显示用,所以只需要向控件传数据即可。
控件是好看,但是大小不能改变,所以这里需要自己实现了,源码作者已经放上。

1.头文件

代码如下(示例):

#ifndef THERMOMETREDLG_H
#define THERMOMETREDLG_H#include <QWidget>
#include <QPropertyAnimation>
#include <QPainter>
#include <QTimer>class thermometreDlg : public QWidget
{Q_OBJECTQ_PROPERTY(qreal value READ getValue WRITE setValue)  //声明属性public:explicit thermometreDlg(QWidget *parent = nullptr);qreal getValue();void setValue(qreal value);void changeValue(qreal value);protected:void paintEvent(QPaintEvent *e);public slots:void startAnimation();signals:private:qreal m_value;qreal curValue;int m_width;QRectF m_rect;int maxValue, minValue;qreal m_radius;QPropertyAnimation *m_valueAnimation;void updateRect();};#endif // THERMOMETREDLG_H

2.实现

代码如下(示例):

#include "thermometredlg.h"
#include <QDebug>thermometreDlg::thermometreDlg(QWidget *parent) : QWidget(parent)
{m_width = 20;maxValue = 100;minValue = 0;m_radius = 1.05;m_value = 0;curValue = m_value;QTimer *at = new QTimer(this);at->start(1000);m_valueAnimation = new QPropertyAnimation(this, "value");m_valueAnimation->setDuration(1000);m_valueAnimation->setEasingCurve(QEasingCurve::OutCubic);m_valueAnimation->setLoopCount(1);connect(at, SIGNAL(timeout()), this, SLOT(startAnimation()));}void thermometreDlg::updateRect()
{m_rect.setX(0);m_rect.setY(20 - height()/2);m_rect.setWidth(m_width);m_rect.setHeight(height() - 40 - m_width* m_radius);
}void thermometreDlg::setValue(qreal value)
{m_value = value;update();
}void thermometreDlg::changeValue(qreal value)
{if(value > maxValue)value = maxValue;if(value < minValue)value = minValue;curValue = value;
}qreal thermometreDlg::getValue()
{return m_value;
}void thermometreDlg::paintEvent(QPaintEvent *e)
{updateRect();QPainter painter(this);QPen pen(Qt::black);painter.translate(this->width()/2, this->height()/2);  //坐标轴移动到中心点painter.setRenderHints(QPainter::TextAntialiasing | QPainter::Antialiasing);  // 启用反锯齿painter.save();//绘制上方的柱状painter.fillRect(m_rect, QColor(168,200, 225));//绘制底部的圆QRectF tmpRect = QRectF(m_rect.bottomLeft(), QPointF(m_width, height()/2- m_width*m_radius));painter.fillRect(tmpRect, QColor(255, 0, 0));painter.setPen(Qt::NoPen);painter.setBrush(QColor(255, 0, 0));painter.drawEllipse(tmpRect.bottomLeft()+QPointF(tmpRect.width()/2, 0),m_width*m_radius, m_width*m_radius);painter.restore();//绘制刻度以及刻度值painter.save();painter.setPen(QColor(Qt::black));int nYCount = (maxValue - minValue)/10+1;qreal perHeight = (m_rect.height())/nYCount;for (int i=0; i<nYCount; ++i) {QPointF basePoint = m_rect.bottomLeft() - QPointF(0, perHeight/2) - QPointF(0, perHeight*i);//左侧大刻度painter.drawLine(basePoint, basePoint+QPointF(-10, 0));for (int j=1; j<10; ++j) {if(i == nYCount -1)continue;painter.drawLine(basePoint-QPointF(0, perHeight/10*j),basePoint-QPointF(5, perHeight/10*j));}painter.drawText(basePoint+QPointF(-28, 4), QString("%1").arg(minValue+i*10));//右侧大刻度basePoint = m_rect.bottomRight() - QPointF(0, perHeight/2) - QPointF(0, perHeight*i);painter.drawLine(basePoint, basePoint+QPointF(10, 0));for (int j=1; j<10; ++j) {if(i == nYCount -1)continue;painter.drawLine(basePoint-QPointF(0, perHeight/10*j),basePoint-QPointF(-5, perHeight/10*j));}}painter.restore();//根据值填充m_rectqreal h = (m_value-minValue)/(maxValue-minValue)*(m_rect.height()-perHeight);if(h<0)h = 0;if(h > m_rect.height())h = m_rect.height();painter.fillRect(m_rect.adjusted(0, m_rect.height()-h-perHeight/2-1 , 0, 0), QColor(255, 0, 0));QWidget::paintEvent(e);
}void thermometreDlg::startAnimation()
{qreal startValue = getValue();m_valueAnimation->setKeyValueAt(0, startValue-1);m_valueAnimation->setKeyValueAt(0.5, curValue+1);m_valueAnimation->setKeyValueAt(1, curValue);m_valueAnimation->setStartValue(startValue-2);m_valueAnimation->start();
}

3、引用

1、用qt实现一个温度计控件
2、Qt编写自定义控件2-进度条标尺
3、Qt动画框架:QPropertyAnimation(属性动画)


相关文章:

QT 实现两款自定义的温度计/湿度控件

文章目录 0 引入1、带有标尺的温度/湿度计控件1.头文件2.核心代码 2、竖起来的温度/湿度计控件1.头文件2.实现 3、引用 0 引入 QT原生控件没有实现如仪表盘或者温度计的控件&#xff0c;只好自己实现&#xff0c;文章代码部分参考引用的文章。直接上图 图一 带有标尺的温度计…...

Fourier分析导论——第4章——Fourier级数的一些应用(E.M. Stein R. Shakarchi)

第 4 章 傅里叶级数的一些应用 Fourier series and analogous expansions intervene very naturally in the general theory of curves and surfaces. In effect, this theory, conceived from the point of view of analysis, deals obviously with the study of arbitra…...

c语言使用fdk_aac库对aac音频解码为pcm

//示例为adts的aac流数据&#xff08;adts数据可以每一包都可以独立解析不需要拼凑&#xff09; //解码数据的采样率同解码前的采样率&#xff0c;如果不满足需求&#xff0c;需要对数据进行重采样 #include <aacdecoder_lib.h>int m_fd -1; int m_fd2 -1;void aac2pc…...

zustand管理工具--React

npm i zustand 1.函数参数必须返回一个对象 对象内部编写状态数据和方法 2.set是用来修改数据的专门方法必须调用它来修改数据 import { useEffect } from "react"; import { create } from "zustand";// 1. 创建store const goodsStore create((set) …...

Elasticsearch内存分析

文章目录 Elasticsearch JVM内存由哪些部分组成Indexing BufferNode Query CacheShard Request CacheField Data CacheSegments Cache查询 非堆内存内存压力mat分析es的jvm缓存监控 Elasticsearch JVM内存由哪些部分组成 官方建议Elasticsearch设置堆内存为32G&#xff0c;因为…...

Alert警告提示(antd-design组件库)简单使用

1.Alert警告提示 警告提示&#xff0c;展现需要关注的信息。 2.何时使用 当某个页面需要向用户显示警告的信息时。 非浮层的静态展现形式&#xff0c;始终展现&#xff0c;不会自动消失&#xff0c;用户可以点击关闭。 组件代码来自&#xff1a; 警告提示 Alert - Ant Design 3…...

Linux提权方法总结

1、内核漏洞提权 利用内核漏洞提取一般三个环节&#xff1a;首先对目标系统进行信息收集&#xff0c;获取系统内核信息及版本信息 第二步&#xff0c;根据内核版本获取对应的漏洞以及exp 第三步&#xff0c;使用exp对目标进行攻击&#xff0c;完成提权 注&#xff1a;此处可…...

力扣第300题 最长递增子序列 c++ 动态规划题 附Java代码

题目 300. 最长递增子序列 中等 相关标签 数组 二分查找 动态规划 给你一个整数数组 nums &#xff0c;找到其中最长严格递增子序列的长度。 子序列 是由数组派生而来的序列&#xff0c;删除&#xff08;或不删除&#xff09;数组中的元素而不改变其余元素的顺序。例…...

Si3262 集成低功耗SOC 三合一智能门锁应用芯片

Si3262 是一款G度集成的低功耗 SOC 芯片&#xff0c;其集成了基于 RISC-V 核的低功耗MCU 和工作在 13.56MHz 的非接触式读写器模块。 读写器模块支持 ISO/IEC 14443 A/B/MIFARE 协议&#xff0c;支持自动载波侦测功能&#xff08;ACD&#xff09;。无需外W其他电路&#xff0c;…...

linux rsyslog介绍

Rsyslog网址&#xff1a;https://www.rsyslog.com/ Rsyslog is the rocket-fast system for log processing. It offers high-performance, great security features and a modular design. While it started as a regular syslogd, rsyslog has evolved into a kind of swis…...

项目部署之安装和配置Canal

1.Canal介绍 Canal是阿里巴巴的一个开源项目&#xff0c;基于java实现&#xff0c;整体已经在很多大型的互联网项目生产环境中使用&#xff0c;包括阿里、美团等都有广泛的应用&#xff0c;是一个非常成熟的数据库同步方案&#xff0c;基础的使用只需要进行简单的配置即可。 …...

基于Skywalking的全链路跟踪实现

在前文“分布式应用全链路跟踪实现”中介绍了分布式应用全链路跟踪的几种实现方法&#xff0c;本文将重点介绍基于Skywalking的全链路实现&#xff0c;包括Skywalking的整体架构和基本概念原理、Skywalking环境部署、SpringBoot和Python集成Skywalking监控实现等。 1、Skywalki…...

Spark Core

Spark Core 本文来自 B站 黑马程序员 - Spark教程 &#xff1a;原地址 第一章 RDD详解 1.1 为什么需要RDD 分布式计算需要 分区控制shuffle控制数据存储、序列化、发送数据计算API等一系列功能 这些功能&#xff0c;不能简单的通过Python内置的本地集合对象&#xff08;如…...

[算法日志]图论: 广度优先搜索(BFS)

[算法日志]图论&#xff1a; 广度优先搜索(BFS) 广度优先概论 ​ 广度优先遍历也是一种常用的遍历图的算法策略&#xff0c;其思想是将本节点相关联的节点都遍历一遍后才切换到相关联节点重复本操作。这种遍历方式类似于对二叉树节点的层序遍历&#xff0c;即先遍历完子节点后…...

Xilinx FPGA SPIx4 配置速度50M约束语句(Vivado开发环境)

qspi_50m.xdc文件&#xff1a; set_property BITSTREAM.GENERAL.COMPRESS TRUE [current_design] set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 4 [current_design] set_property BITSTREAM.CONFIG.CONFIGRATE 50 [current_design] set_property CONFIG_VOLTAGE 3.3 [curren…...

Linux Shell和权限

目录 Shell命令及运行原理 权限 1.文件基本属性 2.文件权限值的表示方法 3.文件访问权限的相关设置方法 3.(1)chmod 组名修改 3.(2)chmod 二进制修改 3.(3)chown 3.(4)chgrp 3.(5)umask 4.目录权限 Shell命令及运行原理 Linux的操作系统&#xff0c;狭义上是…...

Git同时配置Gitee和GitHub

Git同时配置Gitee和GitHub 一、删除原先ssh密钥二、生成密钥 这里的同时配置是针对于之前配置过单个gitee或者github而言的&#xff0c;如果需要看git从安装开始的配置&#xff0c;则可以看这一篇文章 git安装配置教程 一、删除原先ssh密钥 在C盘下用户/用户名/.ssh文件下找到…...

IGP高级特性简要介绍(OSPF-上篇)

OSPF高级特性 一、OSPF_提升故障收敛及网络恢复速度 1.FRR与BFD快速恢复故障 1.1 FRR 在传统转发模式下&#xff0c;当到达同一个目的网络存在多条路由时&#xff0c;路由器总是选择最优路由使用&#xff0c;并且下发到FIB表指导数据转发。 当最优路由故障时&#xff0c;需…...

Oracle-Ogg集成模式降级为经典模式步骤

前言: Ogg集成模式降级为经典模式的场景比较少&#xff0c;因为降级为经典模式会导致无法支持压缩表同步&#xff0c;XA事务&#xff0c;多线程模式&#xff0c;PDB模式同步等功能&#xff0c;除非遇到集成模式暂时无法解决的bug或者环境不支持集成模式&#xff0c;比如DG备库环…...

链表面试OJ题(1)

今天讲解两道链表OJ题目。 1.链表的中间节点 给你单链表的头结点 head &#xff0c;请你找出并返回链表的中间结点。 如果有两个中间结点&#xff0c;则返回第二个中间结点。 示例 输入&#xff1a;head [1,2,3,4,5] 输出&#xff1a;[3,4,5] 解释&#xff1a;链表只有一个…...

树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法

树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作&#xff0c;无需更改相机配置。但是&#xff0c;一…...

day52 ResNet18 CBAM

在深度学习的旅程中&#xff0c;我们不断探索如何提升模型的性能。今天&#xff0c;我将分享我在 ResNet18 模型中插入 CBAM&#xff08;Convolutional Block Attention Module&#xff09;模块&#xff0c;并采用分阶段微调策略的实践过程。通过这个过程&#xff0c;我不仅提升…...

Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)

概述 在 Swift 开发语言中&#xff0c;各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过&#xff0c;在涉及到多个子类派生于基类进行多态模拟的场景下&#xff0c;…...

理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端

&#x1f31f; 什么是 MCP&#xff1f; 模型控制协议 (MCP) 是一种创新的协议&#xff0c;旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议&#xff0c;它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...

【配置 YOLOX 用于按目录分类的图片数据集】

现在的图标点选越来越多&#xff0c;如何一步解决&#xff0c;采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集&#xff08;每个目录代表一个类别&#xff0c;目录下是该类别的所有图片&#xff09;&#xff0c;你需要进行以下配置步骤&#x…...

第 86 场周赛:矩阵中的幻方、钥匙和房间、将数组拆分成斐波那契序列、猜猜这个单词

Q1、[中等] 矩阵中的幻方 1、题目描述 3 x 3 的幻方是一个填充有 从 1 到 9 的不同数字的 3 x 3 矩阵&#xff0c;其中每行&#xff0c;每列以及两条对角线上的各数之和都相等。 给定一个由整数组成的row x col 的 grid&#xff0c;其中有多少个 3 3 的 “幻方” 子矩阵&am…...

selenium学习实战【Python爬虫】

selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...

JavaScript基础-API 和 Web API

在学习JavaScript的过程中&#xff0c;理解API&#xff08;应用程序接口&#xff09;和Web API的概念及其应用是非常重要的。这些工具极大地扩展了JavaScript的功能&#xff0c;使得开发者能够创建出功能丰富、交互性强的Web应用程序。本文将深入探讨JavaScript中的API与Web AP…...

【Redis】笔记|第8节|大厂高并发缓存架构实战与优化

缓存架构 代码结构 代码详情 功能点&#xff1a; 多级缓存&#xff0c;先查本地缓存&#xff0c;再查Redis&#xff0c;最后才查数据库热点数据重建逻辑使用分布式锁&#xff0c;二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...

若依登录用户名和密码加密

/*** 获取公钥&#xff1a;前端用来密码加密* return*/GetMapping("/getPublicKey")public RSAUtil.RSAKeyPair getPublicKey() {return RSAUtil.rsaKeyPair();}新建RSAUti.Java package com.ruoyi.common.utils;import org.apache.commons.codec.binary.Base64; im…...