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

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、难点

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

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


http://www.kler.cn/a/377199.html

相关文章:

  • NewStar CTF 2024 misc WP
  • 研究大语言模型在心理保健智能顾问的有效性和挑战
  • 线程池执行流程
  • 【缓存与加速技术实践】Redis数据类型
  • Kafka 可观测性最佳实践
  • 求平面连接线段组成的所有最小闭合区间
  • 11.Three.js使用indexeddb前端缓存模型优化前端加载效率
  • 「Mac畅玩鸿蒙与硬件23」鸿蒙UI组件篇13 - 自定义组件的创建与使用
  • vscode clangd for cuda 插件配置
  • 华为机试HJ19 简单错误记录
  • 管家婆财贸ERP BB087.销售单复制一行
  • 第二十五章 Vue父子通信之sync修饰符
  • JavaScript 生成二维码
  • 【棋盘覆盖——匈牙利算法】
  • Vue main.js引入全局progress组件原型实例,加载中动画组件原型实例
  • 在B端管理系统中,复杂或者DIY功能,都依赖哪些编辑器/设计器
  • 从技术与市场角度看:3D 创作软件与信创系统的 “距离”
  • node.js下载、安装、设置国内镜像源(永久)(Windows11)
  • Django-中间件
  • 如何理解ref,toRef,和toRefs
  • 《云计算网络技术与应用》实训8-1:OpenvSwitch简单配置练习
  • 写一个 EventBus 实现微信小程序的发布订阅,支持全局消息通知、跨页面通信,高效好用!
  • 形态学操作篇 原理公式代码齐活
  • Redis常见面试题:ZSet底层数据结构,SDS、压缩列表ZipList、跳表SkipList
  • 《GBDT 算法的原理推导》 11-13初始化模型 公式解析
  • flask框架用法介绍(二):Flask和forms