Qt自定义控件:汽车速度表

1、功能

制作一个汽车速度表

2、实现

从外到内进行绘制,初始化画布,画渐变色外圈,画刻度,写刻度文字,画指针,画扇形,画内圈渐变色,画黑色内圈,写当前值

3、效果

汽车速度表

4、源码
a、头文件
#ifndef CARDASHBOARD_H
#define CARDASHBOARD_H

#include <QTimer>
#include <QWidget>

class CarDashboard : public QWidget {
  Q_OBJECT

 public:
  CarDashboard(QWidget *parent = nullptr);
  ~CarDashboard();

 protected:
  void paintEvent(QPaintEvent *event);

 private:
  void startSpeed();
  void initCanvas(QPainter &painter);
  void drawOutterShine(QPainter &painter);
  void drawScale(QPainter &painter);
  void drawScaleText(QPainter &painter);
  void drawPointer(QPainter &painter);
  void drawSector(QPainter &painter);
  void drawInnerShine(QPainter &painter);
  void drawInnerBlack(QPainter &painter);
  void drawCurrentValue(QPainter &painter);

 private:
  const int kScaleAngle = 240;   // 刻度扇形角度
  const int kScaleNum = 60;      // 刻度数量
  const int kLengthScale = 5;    // 长刻度与刻度比例
  const int kOneScaleValue = 4;  // 一个刻度对应值

  double av_angle_ = 0;               // 平均角度
  int start_rotate_angle_clock_ = 0;  // 起始旋转角度(顺时针)(推算出来的)
  int start_rotate_angle_ = 0;  // 起始旋转角度(逆时针)(推算出来的)

  int pointer_dir_ = 0;        // 指针旋转方向
  int scale_value_ = 0;        // 刻度值
  int height_half_ = 0;        // 高度一半
  int min_unit_ = 0;           // 最小单位值
  int font_size_ = 0;          // 字体大小
  int scale_text_radius_ = 0;  // 刻度文字半径
  int indent_value_ = 0;       // 刻度缩进值

  QTimer *timer_ = nullptr;  // 定时器
};
#endif  // CARDASHBOARD_H
b、源文件
#include "cardashboard.h"

#include <QPainter>
#include <QtMath>

CarDashboard::CarDashboard(QWidget *parent) : QWidget(parent) {
  av_angle_ = kScaleAngle * 1.0 / kScaleNum;
  start_rotate_angle_clock_ = -kScaleAngle / 2 + 270;
  start_rotate_angle_ = kScaleAngle / 2 + 90;
  startSpeed();
}

CarDashboard::~CarDashboard() {}

void CarDashboard::startSpeed() {
  timer_ = new QTimer(this);
  connect(timer_, &QTimer::timeout, [=]() {
    update();
    if (pointer_dir_ == 0) {
      scale_value_++;
      if (scale_value_ >= kScaleNum) {
        pointer_dir_ = 1;
      }
    } else if (pointer_dir_ == 1) {
      scale_value_--;
      if (scale_value_ == 0) {
        pointer_dir_ = 0;
      }
    }
  });
  timer_->setInterval(50);
  timer_->start();
}

void CarDashboard::initCanvas(QPainter &painter) {
  painter.setRenderHint(QPainter::Antialiasing, true);
  // 黑色背景
  painter.setBrush(Qt::black);
  painter.drawRect(rect());
  painter.setBrush(Qt::NoBrush);
  painter.translate(QPoint(width() / 2, height() * 0.6));

  height_half_ = height() / 2;                            // 高度一半
  min_unit_ = height() / 16;                              //  最小单位值
  font_size_ = min_unit_ * 2 / 5;                         // 字体大小
  scale_text_radius_ = height_half_ - min_unit_ * 7 / 8;  // 刻度文字半径
  indent_value_ = min_unit_ / 8;                          // 刻度缩进大
}

void CarDashboard::drawOutterShine(QPainter &painter) {
  const int radius = height_half_ + min_unit_ / 2;
  painter.save();
  QRect rect(-radius, -radius, radius * 2, radius * 2);
  QRadialGradient gradient(0, 0, radius);
  gradient.setColorAt(1.0, QColor(255, 0, 0, 200));
  gradient.setColorAt(0.97, QColor(255, 0, 0, 120));
  gradient.setColorAt(0.92, QColor(0, 0, 0, 0));
  gradient.setColorAt(0.0, QColor(0, 0, 0, 0));
  painter.setPen(Qt::NoPen);
  painter.setBrush(gradient);
  painter.drawPie(rect, start_rotate_angle_ * 16, -av_angle_ * kScaleNum * 16);
  painter.restore();
}

void CarDashboard::drawScale(QPainter &painter) {
  painter.save();
  painter.setPen(QPen(Qt::white, 3));
  painter.rotate(start_rotate_angle_clock_);
  for (int i = 0; i <= kScaleNum; i++) {
    if (i >= 40) {
      painter.setPen(QPen(Qt::red, 3));
    }
    if (i % kLengthScale == 0) {  // 长刻度
      painter.drawLine(height_half_ - min_unit_ / 2, 0,
                       height_half_ - indent_value_, 0);
    } else {  // 短刻度
      painter.drawLine(height_half_ - min_unit_ / 4, 0,
                       height_half_ - indent_value_, 0);
    }
    painter.rotate(av_angle_);
  }
  painter.restore();
}

// 这个函数是难点
void CarDashboard::drawScaleText(QPainter &painter) {
  painter.save();
  painter.setPen(QPen(Qt::white, 3));
  QFont font("Arial", font_size_);
  font.setBold(true);
  painter.setFont(font);
  for (int i = 0; i <= kScaleNum; i++) {
    if (i % kLengthScale == 0) {
      // 保存坐标
      painter.save();
      // 正弦 余弦
      int del_x = qCos(qDegreesToRadians(start_rotate_angle_ - av_angle_ * i)) *
                  scale_text_radius_;
      int del_y = qSin(qDegreesToRadians(start_rotate_angle_ - av_angle_ * i)) *
                  scale_text_radius_;
      // 平移坐标系
      painter.translate(QPoint(del_x, -del_y));
      // 选择坐标系
      painter.rotate(-kScaleAngle / 2 + av_angle_ * i);
      // 绘制文字
      painter.drawText(
          QRect(-min_unit_ / 2, -min_unit_ / 2, min_unit_, min_unit_),
          Qt::AlignCenter, QString::number(i * kOneScaleValue));
      // 恢复坐标
      painter.restore();
    }
  }
  painter.restore();
}

void CarDashboard::drawPointer(QPainter &painter) {
  painter.save();
  painter.setPen(Qt::NoPen);
  painter.setBrush(Qt::white);
  const QPointF point[4]{
      QPointF(0, 0.0),
      QPointF(height_half_ - min_unit_ * 5 / 2, -min_unit_ / 32.0),
      QPointF(height_half_ - min_unit_ * 5 / 2, min_unit_ / 32.0),
      QPointF(0, min_unit_ / 3.0),
  };
  painter.rotate(start_rotate_angle_clock_ + av_angle_ * scale_value_);
  painter.drawPolygon(point, 4);
  painter.restore();
}

void CarDashboard::drawSector(QPainter &painter) {
  const int radius = height_half_ + min_unit_ / 2;
  painter.save();
  painter.setPen(Qt::NoPen);
  painter.setBrush(QColor(255, 0, 0, 50));
  QRect rect(-radius, -radius, radius * 2, radius * 2);
  painter.drawPie(rect, start_rotate_angle_ * 16,
                  -av_angle_ * scale_value_ * 16);
  painter.restore();
}

void CarDashboard::drawInnerShine(QPainter &painter) {
  painter.setBrush(QColor(255, 0, 0, 150));
  painter.drawEllipse(QPoint(0, 0), min_unit_ * 2, min_unit_ * 2);
}

void CarDashboard::drawInnerBlack(QPainter &painter) {
  painter.setBrush(Qt::black);
  painter.drawEllipse(QPoint(0, 0), min_unit_ * 3 / 2, min_unit_ * 3 / 2);
}

void CarDashboard::drawCurrentValue(QPainter &painter) {
  painter.setPen(QPen(Qt::white, 3));
  QFont font("Arial", font_size_ * 3 / 2);
  font.setBold(true);
  painter.setFont(font);
  painter.drawText(QRect(-min_unit_, -min_unit_, min_unit_ * 2, min_unit_),
                   Qt::AlignCenter,
                   QString::number(scale_value_ * kOneScaleValue));
  font.setPointSize(font_size_ * 3 / 4);
  painter.setFont(font);
  painter.drawText(
      QRect(-min_unit_, min_unit_ / 2, min_unit_ * 2, min_unit_ / 2),
      Qt::AlignCenter, "Km/h");
}

void CarDashboard::paintEvent(QPaintEvent *event) {
  Q_UNUSED(event);
  QPainter painter(this);
  // 初始化画布
  initCanvas(painter);
  // 画外圈渐变色
  drawOutterShine(painter);
  // 画刻度
  drawScale(painter);
  // 写刻度文字
  drawScaleText(painter);
  // 画指针
  drawPointer(painter);
  // 画扇形
  drawSector(painter);
  // 画内圈渐变色
  drawInnerShine(painter);
  // 画黑色内圈
  drawInnerBlack(painter);
  // 当前值
  drawCurrentValue(painter);
}
5、难点

这里难点使用正弦和余弦计算绘制刻度字。

对你有用就点个赞👍,以后需要用到就收藏⭐

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Rust 力扣 - 1461. 检查一个字符串是否包含所有长度为 K 的二进制子串

文章目录 题目描述题解思路题解代码题目链接 题目描述 题解思路 长度为k的二进制子串所有取值的集合为[0, sum(k)]&#xff0c;其中sum(k)为1 2 4 … 1 << (k - 1) 我们只需要创建一个长度为sum(k) 1的数组 f &#xff0c;其中下标为 i 的元素用来标记字符串中子串…

【2024年11月高质量国际学术会议推荐1】拓展学术视野,点亮学术之路!开启科研新征程!——数学|物理|电离|能源|遥感|交通各大领域...

【2024年11月高质量国际学术会议推荐1】拓展学术视野&#xff0c;点亮学术之路&#xff01;开启科研新征程&#xff01;——数学|物理|电离|能源|遥感|交通各大领域… 【2024年11月高质量国际学术会议推荐1】拓展学术视野&#xff0c;点亮学术之路&#xff01;开启科研新征程&…

沪深A股上市公司数据报告分析

数据分析报 目录 数据分析报告 1.引言 1.1 背景介绍 1.2 报告目的 1.3 报告范围 1.4 关键术语定义 2. 数据收集与预处理 2.1 数据来源概述 2.2 数据收集过程 2.3 数据预处理步骤 3. 数据可视化 3.1分析地区对公司数量的影响 3.2分析行业分类是否影响公…

ImportError: Install xlrd >= 1.0.0 for Excel support

文章目录 一、报错问题二、问题解释三、解决方法 一、报错问题 问题描述&#xff1a; python2.7使用pandas读取excel文件时报错ImportError: Install xlrd > 1.0.0 for Excel support。 问题代码&#xff1a; # codingutf-8import pandas as pddata pd.read_excel(D:\Wo…

【Linux】make/makefile/gdb调试技巧/进度条小程序

目录 一、sudo提权&#xff1a; 二、自动化构建工具make与Makefile makefile&#xff1a; make&#xff1a; 是否重新执行make&#xff1a; 伪目标&#xff1a; 三、进度条小程序&#xff1a; 四、Linux调试器gdb&#xff1a; 1.、前景提要&#xff1a; 2、进入与退出…

Flutter实战短视频课程

1、课程导学 一套代研运行多蜡 体州一致&#xff0c;目胜能优昇 未来大趋势 不改交原生项目的基础上&#xff0c;扩展Flutter能力 Flutter原生灵话切涣 0入侵 最简单、最通用 最新Flutter 3,x新特性讲解 大量flutter官方组件和api学习 最常用的第三方库使用及原理解析 自研组…

程序员的新电脑到手后应该做哪些必要设置?

吃水果要剥皮&#xff0c;用 Windows 也一样&#xff0c;如果是 Win 10 的话&#xff0c;刚装完系统就需要屏蔽一些功能&#xff0c;才能更顺畅快速&#xff1a; 隐藏任务栏上的搜索框和小娜&#xff0c;需要搜索时wins就会出现禁用开始目录的app自动推荐删除人脉图标删除任务…

unocss 添加支持使用本地 svg 预设图标,并支持更改大小

安装 pnpm install iconify/utils 在配置文件 unocss.config.ts&#xff1a; presets > presetIcons 选项中 通过 FileSystemIconLoader 加载本地图标&#xff0c;并指定目录。 import presetWeapp from unocss-preset-weapp import { extractorAttributify, transformer…

Zig 语言通用代码生成器:逻辑,发布冒烟测试版二之二

Zig 语言通用代码生成器&#xff1a;逻辑&#xff0c;发布冒烟测试版二之二 Zig 语言通用代码生成器&#xff1a;逻辑&#xff0c;已发布冒烟测试版二。此版本完善了代码生成物。支持多对多关系。修复了所有单域动词。并有更多缺陷修复。暂时不支持图片类型。暂时不支持日期和…

Vue3的router和Vuex的学习笔记整理

一、路由的基本搭建 1、安装 npm install vue-router --registryhttps://registry.npmmirror.com 2、配置路由模块 第一步&#xff1a;src/router/index.js创建文件 第二步&#xff1a;在src/view下面创建两个vue文件&#xff0c;一个叫Home.vue和About.vue 第三步&#x…

远程连接服务

目录 一、远程连接服务器简介 二、连接加密技术简介 三、认证阶段 四、ssh实验 1.修改ssh服务器的端口号 2.拒绝root账户远程登录 3.允许特定用户ssh登录&#xff0c;其他用户无法登录 4.ssh-keygen 一、远程连接服务器简介 概念&#xff1a; 远程连接服务器通过文字或…

JS中面向对象

一、对象 1.认识对象 在JavaScript中&#xff0c;对象&#xff08;Object&#xff09;是一种复合数据类型&#xff0c;它允许你存储键值对。对象的属性是连接到对象的变量&#xff0c;而函数或方法是属于对象的函数。 JavaScript中的对象类似于哈希表&#xff0c;其中键可以是…

【工具变量】“宽带中国”试点城市名单匹配数据集(2000-2023年)

参照秦文晋&#xff08;2022&#xff09;的《网络基础设施建设对数字经济发展的影响研究——基于"宽带中国"试点政策的准自然实验》一文中的做法&#xff0c;将选为“宽带中国”试点城市的虚拟变量作为核心解释变量&#xff0c;当一个城市被批复成为“宽带中国”试点…

Matlab车牌识别课程设计报告(附源代码)

Matlab车牌识别系统 分院&#xff08;系&#xff09; 信息科学与工程 专业 学生姓名 学号 设计题目 车牌识别系统设计 内容及要求&#xff1a; 车牌定位系统的目的在于正确获取整个图像中车牌的区域&#xff0c; 并识别出车牌号。通过设计实现车牌识别系…

基于OSS搭建在线教育视频课程分享网站

OSS对象存储服务是海量、安全、低成本、高持久的存储服务。适合于存储大规模非结构化数据&#xff0c;如图片、视频、备份文件和容器/虚拟机镜像等。 安装nginx wget https://nginx.org/download/nginx-1.20.2.tar.gz yum -y install zlib zlib-devel gcc-c pcre-devel open…

Edit Data. Create Cell Editors. Validate User Input 编辑数据。创建 Cell Editors。验证用户输入

Goto Data Grid 数据网格 Edit Data. Create Cell Editors. Validate User Input 编辑数据。创建 Cell Editors。验证用户输入 Get and Modify Cell Values in Code 在代码中获取和修改单元格值 仅当 Grid 及其列已完全初始化时&#xff0c;才使用以下方法。如果需要在表单仍…

【JavaEE初阶 — 多线程】Thread的常见构造方法&属性

目录 Thread类的属性 1.Thread 的常见构造方法 2.Thread 的几个常见属性 2.1 前台线程与后台线程 2.2 setDaemon() 2.3 isAlive() Thread类的属性 Thread 类是JVM 用来管理线程的一个类&#xff0c;换句话说&#xff0c;每个线程都有一个唯一的Thread 对象与之关联&am…

【设计模式】如何用C++实现依赖倒置

【设计模式】如何用C实现依赖倒置 一、什么是依赖倒置&#xff1f; 依赖倒置原则&#xff08;Dependency Inversion Principle&#xff0c;DIP&#xff09;是SOLID面向对象设计原则中的一项。它的核心思想是&#xff1a; 高层模块不应该依赖于低层模块&#xff0c;两者都应该…

【文献及模型、制图分享】中国城市家庭食物浪费行为及减量对策——以郑州市为例

文献介绍 减少食物浪费是保障粮食安全的重要途径。家庭是社会的基本单元&#xff0c;不仅是产生食物浪费的主要场景&#xff0c;也是开展反食品浪费教育的重要场所。本文以河南省郑州市为例&#xff0c;基于1315份城市家庭食物浪费一手调查数据&#xff0c;首次将城市家庭食物…

【Linux】从零开始使用多路转接IO --- poll

碌碌无为&#xff0c;则余生太长&#xff1b; 欲有所为&#xff0c;则人生苦短。 --- 中岛敦 《山月记》--- 从零开始使用多路转接IO 1 前言1 poll接口介绍3 代码编写4 总结 1 前言 上一篇文章我们学习了多路转接中的Select&#xff0c;其操作很简单&#xff0c;但有一些缺…