基于Qt的速度仪表盘控件实现

news2024/11/25 0:42:36

本文将详细讲解一个基于Qt的速度仪表盘控件的实现过程,并对代码进行详细的注释说明。该控件可以模拟汽车仪表盘的外观,并通过滑动条动态改变速度显示。本文将从代码结构、绘制组件到实现细节进行讲解,帮助您理解如何使用Qt框架自定义绘制控件。

在这里插入图片描述

1. 仪表盘控件构造函数

Dashboard类的构造函数中,设置了控件的背景颜色为黑色:

Dashboard::Dashboard(QWidget *parent) : QWidget(parent)
{
    // 设置背景色为黑色
    QPalette bgpal = palette();
    bgpal.setColor(QPalette::Background, QColor(0, 0, 0));
    setPalette(bgpal);
}

在这里,我们通过QPalette对象设置控件的背景色为黑色。如果需要其他背景颜色,只需修改QColor(0,0,0)即可。


2. 设置最大刻度

函数setScale允许我们设置速度表盘的最大值(例如120KM/h):

void Dashboard::setScale(const qreal max)
{
    // 设置最大刻度值
    MaxScale = max;
    // 更新控件显示
    update();
}

MaxScale保存了仪表盘的最大刻度值,调用update()触发控件重绘,从而更新显示。


3. paintEvent 绘制事件

paintEvent是绘制控件的核心函数,负责绘制仪表盘的所有元素:

void Dashboard::paintEvent(QPaintEvent*)
{
    // 创建QPainter对象
    QPainter painter(this);
    int width = this->width();
    int height = this->height();
    
    // 计算半径,使得仪表盘始终适应窗口尺寸
    int radius = ((width > height) ? height : width) / 2;

    // 移动画笔中心到控件的中下部
    painter.translate(width / 2, height * 0.6);

    // 启用抗锯齿,提高绘图质量
    painter.setRenderHint(QPainter::Antialiasing, true);
    
    // 设置无笔绘制,只填充颜色
    painter.setPen(Qt::NoPen);
    
    // 设置画刷颜色为紫色
    painter.setBrush(QColor(138, 43, 226));

    // 调用各个绘制函数,绘制仪表盘不同部分
    DrawDigital(painter, radius - 10); // 绘制刻度数字
    DrawCircle(painter, radius - 35);  // 绘制外圆
    DrawSmallScale(painter, radius - 60); // 绘制小刻度
    DrawText(painter, radius / 5); // 绘制中心文字
    DrawPointer(painter, radius - 100); // 绘制指针
}

该函数首先通过QPainter对象进行绘图,确定控件的宽高,并计算适应当前窗口的半径。translate函数将画笔的原点移动到控件的中下部,使得仪表盘绘制的中心位于该位置。启用了抗锯齿(Antialiasing)以确保绘制质量较高。

接下来,调用了多个辅助函数来绘制仪表盘的不同部分,包括刻度、外圆、指针等。


4. 绘制组件函数

下面是各个辅助函数的讲解,每个函数负责绘制仪表盘的一部分。

4.1 绘制刻度数字 (DrawDigital)

该函数负责在仪表盘的外圈上绘制数字刻度:

void Dashboard::DrawDigital(QPainter& painter, int radius)
{
    // 设置画笔颜色为用户自定义颜色
    painter.setPen(m_color);
    QFont font;
    font.setFamily("Cambria");
    font.setPointSize(12);
    painter.setFont(font);

    // 依次绘制0, 10, 20...等刻度数字
    for (int i = 0; i < 13; ++i) {
        QPointF point(0, 0);
        painter.save();

        // 计算数字的位置
        point.setX(radius * qCos(((210 - i * 20) * M_PI) / 180));
        point.setY(radius * qSin(((210 - i * 20) * M_PI) / 180));
        painter.translate(point.x(), -point.y());

        // 旋转文字,使其朝向正确
        painter.rotate(-120 + i * 20);

        // 在计算的位置绘制数字
        painter.drawText(-15, 0, 30, 20, Qt::AlignCenter, QString::number(i * (MaxScale) / 12));
        painter.restore();
    }
    // 还原画笔状态
    painter.setPen(Qt::NoPen);
}

此函数使用正弦和余弦函数来计算每个数字的绘制位置,并通过旋转(rotate)保证数字的正确方向。

4.2 绘制外圆 (DrawCircle)

绘制仪表盘的外圈,包括渐变色效果:

void Dashboard::DrawCircle(QPainter& painter, int radius)
{
    painter.save();

    // 定义外圈和内圈路径
    QPainterPath outRing, inRing;
    outRing.moveTo(0, 0);
    inRing.moveTo(0, 0);

    // 绘制外圈弧形
    outRing.arcTo(-radius, -radius, 2 * radius, 2 * radius, -31, 242);
    inRing.addEllipse(-radius + 20, -radius + 20, 2 * (radius - 20), 2 * (radius - 20));
    outRing.closeSubpath();

    // 设置渐变色效果
    QRadialGradient radialGradient(0, 0, radius, 0, 0);
    radialGradient.setColorAt(0.93, m_color);  // 外部为自定义颜色
    radialGradient.setColorAt(1, QColor(0, 0, 0));  // 内部为黑色

    // 使用渐变色进行填充
    painter.setBrush(radialGradient);
    painter.drawPath(outRing.subtracted(inRing));
    painter.restore();
}

该函数绘制了一个带有渐变色效果的外圈。arcTo用于绘制弧形外圈,addEllipse用于绘制内圈,渐变色效果通过QRadialGradient实现。

4.3 绘制指针 (DrawPointer)

指针的绘制逻辑如下:

void Dashboard::DrawPointer(QPainter& painter, int radius)
{
    QPainterPath pointPath;
    // 定义指针的路径(形状)
    pointPath.moveTo(10, 0);
    pointPath.lineTo(1, -radius - 25);  // 指针的长度
    pointPath.lineTo(-1, -radius - 25);
    pointPath.lineTo(-10, 0);
    pointPath.arcTo(-10, 0, 20, 20, 180, 180);

    painter.save();

    // 设置渐变颜色
    QRadialGradient radialGradient(0, 0, radius, 0, 0);
    radialGradient.setColorAt(0, QColor(0, 199, 140, 150));
    radialGradient.setColorAt(1, QColor(255, 153, 18, 150));

    // 根据当前速度旋转指针
    painter.rotate(240 / (MaxScale) * degRotate - 120);
    painter.setBrush(radialGradient);

    // 绘制指针
    painter.drawPath(pointPath);
    painter.restore();
}

该函数绘制了速度表的指针。QPainterPath用于定义指针的形状,rotate函数根据当前速度值旋转指针,使其指向正确的位置。


5. 使用滑动条控制速度显示

MainWindow类中,通过滑动条来动态改变速度表的值:

void MainWindow::on_horizontalSlider_sliderMoved(int position)
{
    ui->widget->valueChanged(position);
}

当滑动条被移动时,position参数表示当前滑块的位置,并通过调用valueChanged函数将其传递给仪表盘控件,进而更新指针的显示位置。


总结

通过本文的讲解,您已经了解了如何使用Qt绘制自定义的速度仪表盘控件。该控件通过QPainter对象和一些数学计算来绘制表盘的刻度、外圈和指针,并且可以通过滑动条动态改变显示的速度值。

为了进一步改进,您可以添加更多功能,比如让指针的移动更平滑、增加不同颜色的主题、设置更多自定义选项等。希望本文能够为您的Qt开发提供帮助。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2195461.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CSRF | GET 型 CSRF 漏洞攻击

关注这个漏洞的其他相关笔记&#xff1a;CSRF 漏洞 - 学习手册-CSDN博客 0x01&#xff1a;GET 型 CSRF 漏洞攻击 —— 理论篇 GET 型 CSRF 漏洞是指攻击者通过构造恶意的 HTTP GET 请求&#xff0c;利用用户的登录状态&#xff0c;在用户不知情的情况下&#xff0c;诱使浏览器…

Cortex-M3/M4/M7 芯片 Fault 分析原理与实战

目录 一、简介1、异常类型2、异常优先级3、同步异步问题4、异常具体类型 二、Fault exception registers1、Control registers1.1 CCR1.2 SHP1.3 SHCSR 2、Status and address registers2.1 HardFault Status Register——HSFR2.2 Configurable Fault Status Register——CFSR2…

《Linux从小白到高手》进阶实操篇:用户及权限有关的实际工作场景应用

List item 本篇为《Linux从小白到高手》进阶实操篇的第一篇&#xff0c;主要介绍分享一些用户及权限有关的实际工作场景应用。 场景1&#xff1a; 实际工作中你一定会碰到如下图所示的情景&#xff1a;本部门有5个组&#xff0c;分别为&#xff1a;①Root组&#xff1a;用户…

Python中对象obj类型确定最pythonic的方式——isinstance()函数

python中确定对象obj的类型&#xff0c;isinstance函数最是优雅&#xff0c;type、issubclass等函数也可以&#xff0c;但终究“曲折”。 (笔记模板由python脚本于2024年10月07日 19:42:38创建&#xff0c;本篇笔记适合喜欢python的coder翻阅) 【学习的细节是欢悦的历程】 Pyth…

Vue2电商项目(七)、订单与支付

文章目录 一、交易业务Trade1. 获取用户地址2. 获取订单信息 二、提交订单三、支付1. 获取支付信息2. 支付页面--ElementUI(1) 引入Element UI(2) 弹框支付的业务逻辑(这个逻辑其实没那么全)(3) 支付逻辑知识点小总结 四、个人中心1. 搭建二级路由2. 展示动态数据(1). 接口(2).…

【Kubernetes】常见面试题汇总(六十)

目录 131. pod 一直处于 pending 状态&#xff1f; 132. helm 安装组件失败&#xff1f; 特别说明&#xff1a; 题目 1-68 属于【Kubernetes】的常规概念题&#xff0c;即 “ 汇总&#xff08;一&#xff09;~&#xff08;二十二&#xff09;” 。 题目 69-113 属于…

企业经营异常怎么解除

经营异常是怎么回事&#xff1f;是什么意思&#xff1f;了解异常原因&#xff1a;我们到所属工商营业执照异常的具体原因。原因可能包括未按时提交年报、未履行即时信息公示义务、公示信息隐瞒真实情况或弄xu作jia、失联等。纠正违规行为&#xff1a;查到了异常原因&#xff0c…

洛谷P5723、P5728、P1428、P1319 Python解析

P5723 完整代码 def is_prime(y):if y < 2:return Falsefor i in range(2, int(y**0.5) 1):if y % i 0:return Falsereturn Truen int(input()) sum_primes 0 x 0if n < 2:print("0") elif n 2:print("2\n1") else:for i in range(2, n 1):i…

计数原理与组合 - 离散数学系列(三)

目录 1. 计数原理的基本概念 加法原理&#xff08;Rule of Sum&#xff09; 乘法原理&#xff08;Rule of Product&#xff09; 2. 排列与组合 排列&#xff08;Permutation&#xff09; 组合&#xff08;Combination&#xff09; 日常生活中的例子 3. 二项式定理 4. 实…

Mysql锁机制解读(敲详细)

目录 锁的概念 全局锁 表级锁 表锁 元数据锁 意向锁 锁的概念 全局锁 表级锁 表锁 元数据锁 主要是对未提交事务&#xff0c;修改表结构造成表结构混乱&#xff0c;进行控制。 在不涉及表结构变化的情况下,元素锁可以忽略。 意向锁 避免有行级锁影响加表级锁&#xff0…

Mysql(六) --- 聚合函数,分组和联合查询

文章目录 前言1.聚合函数1.1.常用的函数1.2.COUNT()1.3.SUM()1.4.AVG()1.5.MIN()、MAX() 2.GROUP BY 分组查询2.1.语法2.2.示例2.3.HAVING 子句 3.联合查询3.1.为什么要进行联合查询3.2.那么是如何进行联合查询的3.3.示例&#xff1a;一个完整的联合查询的过程3.4.内连接3.5.外…

Error:WPF项目中使用oxyplot,错误提示命名空间中不存在“Plot”名称

在OxyPlot中&#xff0c;<oxy:PlotView>和<oxy:Plot>都是用来显示图表的控件&#xff0c;在WPF项目中使用oxyplot之前&#xff0c;先通过NuGet安装依赖包&#xff1a;OxyPlot.Wpf。 <oxy:PlotView>和<oxy:Plot>使用示例&#xff1a; <oxy:PlotVie…

【算法】双指针(续)

一、盛最多水的容器 11. 盛最多水的容器 - 力扣&#xff08;LeetCode&#xff09; 给定一个长度为 n 的整数数组 height 。有 n 条垂线&#xff0c;第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线&#xff0c;使得它们与 x 轴共同构成的容器可以容纳最多…

OJ在线评测系统 微服务 OpenFeign调整后端下 nacos注册中心配置 不给前端调用的代码 全局引入负载均衡器

OpenFeign内部调用二 4.修改各业务服务的调用代码为feignClient 开启nacos注册 把Client变成bean 该服务仅内部调用&#xff0c;不是给前端的 将某个服务标记为“内部调用”的目的主要有以下几个方面&#xff1a; 安全性: 内部API通常不对外部用户公开&#xff0c;这样可以防止…

Nginx05-基础配置案例

零、文章目录 Nginx05-基础配置案例 1、案例需求 &#xff08;1&#xff09;有如下访问 http://192.168.119.161:8081/server1/location1 访问的是&#xff1a;index_sr1_location1.htmlhttp://192.168.119.161:8081/server1/location2 访问的是&#xff1a;index_sr1_loca…

慢接口分析与优化总结

文章目录 1. 慢接口优化的意义2. 接口耗时构成3. 优化技巧3.1. 内部代码逻辑异步执行[异步思想]并行优化拒绝阻塞等待预分配与循环使用[池化思想]线程池合理设计锁粒度避免过粗优化程序结构 3.2. 缓存恰当引入缓存[空间换时间思想]缓存延迟优化提前初始化缓存[预取思想] 3.3. 数…

工具函数(截取文本第一个字为图片)

const subStringToImage (params) > {const { str ,color #FFF,background #4F54FF,size 60,fontSize 20 } paramsif(str.length < 0) return console.error(字符不能为空!)const text str.slice(0, 1)const canvas document.createElement(canvas)const ctx …

github 国内文件加速下载

参看;https://www.cnblogs.com/ting1/p/18356265 在源网址前加上 https://hub.gitmirror.com/ 或https://mirror.ghproxy.com/&#xff0c;例如&#xff1a; https://hub.gitmirror.com/https://github.com/t1m0thyj/WinDynamicDesktop/releases/download/v5.4.1/WinDynamicD…

算法题总结(十)——二叉树上

#二叉树的递归遍历 // 前序遍历递归LC144_二叉树的前序遍历 class Solution {public List<Integer> preorderTraversal(TreeNode root) {List<Integer> result new ArrayList<Integer>(); //也可以把result 作为全局变量&#xff0c;只需要一个函数即可。…

公开数据集网站分享

参考链接&#xff1a;常用的医学组织切片细胞图像数据集_细胞分割数据集-CSDN博客文章浏览阅读1.3w次&#xff0c;点赞32次&#xff0c;收藏133次。乳腺癌细胞图像数据集、血细胞图像数据集、HE染色切片、疟疾细胞图像图像识别、分类、分割_细胞分割数据集https://blog.csdn.ne…