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

1、功能

制作一个汽车速度表

2、实现

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

3、效果
4、源码
a、头文件
cpp 复制代码
#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、源文件
cpp 复制代码
#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、难点

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

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

相关推荐
----云烟----6 小时前
QT中QString类的各种使用
开发语言·qt
「QT(C++)开发工程师」11 小时前
【qt版本概述】
开发语言·qt
一路冰雨15 小时前
Qt打开文件对话框选择文件之后弹出两次
开发语言·qt
老赵的博客16 小时前
QT 自定义界面布局要诀
开发语言·qt
码码哈哈0.016 小时前
VSCode 2022 离线安装插件QT VSTOOl报错此扩展不能安装在任何当前安装的产品上。
ide·vscode·qt
feiyangqingyun20 小时前
Qt/C++离线地图的加载和交互/可以离线使用/百度和天地图离线/支持手机上运行
c++·qt·qt天地图·qt离线地图·qt地图导航
gz94561 天前
windows下,用CMake编译qt项目,出现错误By not providing “FindQt5.cmake“...
开发语言·qt
「QT(C++)开发工程师」1 天前
Ubuntu 26.04 LTS 大升级:Qt 6 成为未来新引擎
qt
兆。2 天前
python实战案例----使用 PyQt5 构建简单的 HTTP 接口测试工具
爬虫·python·qt
喝哈喝哈2 天前
pycharm中配置pyqt5
python·qt·pycharm