Qt:汽车仪表盘控件

9 篇文章 1 订阅

Qt:汽车仪表盘

前言

基于QWidget实现的汽车仪表盘,包括发动机转速表,迈速表,油表,发动机水箱温度计,并且分别提供了接口。仪表盘的实现思路是计算各个表盘的坐标并进行绘制,尽可能减少贴图的使用。
效果图如下,代码自取,请放心食用。有不懂地方可留言交流,会不定期回复。

源码

这里提供基础的源码,包含了实现仪表盘的基本思路,其它素材可根据需求自行替换。

fr_armaturenbrett.h

#ifndef FRARMATURENBRETT_H
#define FRARMATURENBRETT_H

#include <QWidget>

class FrArmaturenbrett : public QWidget {
  Q_OBJECT
public:
  enum Gear {
    kGear_1 = 1,
    kGear_2,
    kGear_3,
    kGear_4,
    kGear_5,
    kGear_6,
    kGear_7,
    kGear_8,
    kGear_D,
    kGear_N,
    kGear_P,
    kGear_R
  };

public:
  explicit FrArmaturenbrett(QWidget *parent = nullptr);

public slots:
  void set_gear(const Gear gear);
  void set_rpm(const int rpm);
  void set_speed(const int speed);
  void set_temperature(const double temperature);
  void set_oil(const int oil);

protected:
  void paintEvent(QPaintEvent *event);

private:
  void draw_tachometer(QPainter& painter);  // 转速表
  void draw_speedometer(QPainter& painter);  // 迈速表
  void draw_gear(QPainter& painter);  // 挡位
  void draw_thermometer(QPainter& painter);  // 水箱温度计
  void draw_oil_meter(QPainter& painter);  // 油表

private:
  Gear _gear;
  int _rpm;
  int _speed;
  double _temperature;
  int _oil;
};

#endif // FRARMATURENBRETT_H

fr_armaturenbrett.cpp

#include "fr_armaturenbrett.h"

#include <qapplication.h>
#include <qpainter.h>
#include <qpainterpath.h>
#include <QtGui/QFontDatabase>

FrArmaturenbrett::FrArmaturenbrett(QWidget *parent) :
  QWidget(parent),
  _gear(kGear_4),
  _rpm(4000),
  _speed(120),
  _temperature(60),
  _oil(80) {

  QFontDatabase::addApplicationFont(":/fonts/DejaVuSans.ttf");
}

void FrArmaturenbrett::set_gear(const FrArmaturenbrett::Gear gear) {
  _gear = gear;
  update();
}

void FrArmaturenbrett::set_rpm(const int rpm) {
  _rpm = rpm;
  update();
}

void FrArmaturenbrett::set_speed(const int speed) {
  _speed = speed;
  update();
}

void FrArmaturenbrett::set_temperature(const double temperature) {
  _temperature = temperature;
  update();
}

void FrArmaturenbrett::set_oil(const int oil) {
  _oil = oil;
  update();
}

void FrArmaturenbrett::paintEvent(QPaintEvent* event) {
  QWidget::paintEvent(event);

  int side = qMin(int(width() / 1.8), height());

  QPainter painter(this);
  painter.setRenderHint(QPainter::Antialiasing);
  painter.translate(width() / 2, height() / 2);
  painter.scale(side / 200.0, side / 200.0);
  painter.setPen(Qt::NoPen);
  painter.setBrush(Qt::NoBrush);

  draw_tachometer(painter);
  draw_speedometer(painter);
  draw_gear(painter);
  draw_thermometer(painter);
  draw_oil_meter(painter);
}

void FrArmaturenbrett::draw_tachometer(QPainter& painter) {
  static QColor normal_color(26, 245, 245, 245);
  static QColor overrun_color(245, 64, 64, 225);

  // 绘制表盘外檐
  painter.save();
  painter.setPen(QPen(normal_color, 1,  Qt::SolidLine));
  QRect rect(-95, -95, 190, 190);
  painter.drawArc(rect, 0, 270 * 16);
  painter.restore();

  // 绘制红色区域
  painter.save();
  static QRectF rectangle_outer(-95, -95, 190, 190);
  static QRectF rectangle_inner(-87, -87, 174, 174);
  painter.setBrush(overrun_color);
  QPainterPath path;
  path.arcTo(rectangle_outer, 0.0, 108.0);
  path.arcTo(rectangle_inner, 108, -108);
  painter.drawPath(path);
  painter.restore();

  // 绘制大刻度
  painter.save();
  painter.setPen(QPen(normal_color, 1,  Qt::SolidLine));
  painter.rotate(90);
  for (int i = 0; i < 21; ++i) {
    painter.drawLine(88, 0, 94, 0);
    painter.rotate(13.5);
  }
  painter.restore();

  // 绘制小刻度
  painter.save();
  painter.setPen(QPen(normal_color, 1,  Qt::SolidLine));
  painter.rotate(90);
  for (int i = 0; i < 100; ++i) {
    painter.drawLine(91, 0, 94, 0);
    painter.rotate(2.7);
  }
  painter.restore();

  // 绘制表盘数字
  painter.save();
  painter.rotate(90);
  painter.setPen(normal_color);
  painter.setFont(QFont("Times", 14));
  for (int i = 0; i < 11; ++i) {
    painter.save();
    if (i > 6) {
      painter.setPen(overrun_color);
    }
    painter.rotate(27.0 * i);
    painter.translate(76, 0);
    painter.rotate(270 - 27.0 * i);
    painter.drawText(QRect(-20, -10, 40, 20), Qt::AlignCenter, QString::number(i));
    painter.restore();
  }
  painter.restore();

  // 绘制指针
  static const QPoint hand[] = {
    QPoint(-4, 0),
    QPoint(0, 94),
    QPoint(4, 0),
    QPoint(0, -6)
  };
  static QColor hand_color(26, 245, 245, 176);
  painter.save();
  painter.setPen(Qt::NoPen);
  painter.setBrush(hand_color);
  painter.rotate(27.0 * (_rpm / 1000.0));
  painter.drawConvexPolygon(hand, 4);
  painter.restore();

  // 绘制文字
  painter.save();
  painter.setPen(normal_color);
  painter.setFont(QFont("DejaVu Sans", 8));
  painter.drawText(QRect(-50, -70, 100, 50), Qt::AlignCenter, "×1000");
  painter.setFont(QFont("DejaVu Sans", 8, 50, true));
  painter.drawText(QRect(-50, 34, 32, 16), Qt::AlignCenter, "RPM");
  painter.restore();
}

void FrArmaturenbrett::draw_speedometer(QPainter& painter) {
  painter.save();

  painter.setPen(QColor(64, 64, 245));
  painter.setFont(QFont("DejaVu Sans", 6, 50, true));
  painter.drawText(QRect(80, 50, 70, 20), Qt::AlignCenter, "SPEED");

  painter.setPen(QColor(26, 245, 245));
  painter.setFont(QFont("DejaVu Sans", 24, 63, true));
  painter.drawText(QRect(80, 50, 70, 50), Qt::AlignBottom | Qt::AlignLeft, QString("%0").arg(QString::number(_speed), 3,'0'));

  painter.setPen(QColor(26, 245, 245));
  painter.setFont(QFont("DejaVu Sans", 8, 63, true));
  painter.drawText(QRect(145, 75, 40, 20), Qt::AlignBottom | Qt::AlignLeft, "km/h");

  painter.restore();
}

void FrArmaturenbrett::draw_gear(QPainter& painter) {
  static QRect gear_rect(0, 0, 80, 80);
  static QRect suffix_rect(48, 48, 32, 32);
  static QFont suffix_font("DejaVu Sans", 16, 63, true);

  painter.save();
  painter.setPen(QPen(QColor(26, 245, 245), 1,  Qt::SolidLine));
  painter.setFont(QFont("DejaVu Sans", 48, 63, true));

  switch (_gear) {
    case kGear_1:
      painter.drawText(gear_rect, Qt::AlignCenter, QString::number(_gear));
      painter.setFont(suffix_font);
      painter.drawText(suffix_rect, Qt::AlignCenter, "st");
    break;
    case kGear_2:
      painter.drawText(gear_rect, Qt::AlignCenter, QString::number(_gear));
      painter.setFont(suffix_font);
      painter.drawText(suffix_rect, Qt::AlignCenter, "nd");
    break;
    case kGear_3:
      painter.drawText(gear_rect, Qt::AlignCenter, QString::number(_gear));
      painter.setFont(suffix_font);
      painter.drawText(suffix_rect, Qt::AlignCenter, "rd");
    break;
    case kGear_4:
    case kGear_5:
    case kGear_6:
    case kGear_7:
    case kGear_8:
      painter.drawText(gear_rect, Qt::AlignCenter, QString::number(_gear));
      painter.setFont(suffix_font);
      painter.drawText(suffix_rect, Qt::AlignCenter, "th");
    break;
    case kGear_D:
      painter.drawText(gear_rect, Qt::AlignCenter, "D");
    break;
    case kGear_N:
      painter.drawText(gear_rect, Qt::AlignCenter, "N");
    break;
    case kGear_P:
      painter.drawText(gear_rect, Qt::AlignCenter, "P");
    break;
    case kGear_R:
      painter.drawText(gear_rect, Qt::AlignCenter, "R");
    break;
    default:
    break;
  }

  painter.restore();
}

void FrArmaturenbrett::draw_thermometer(QPainter& painter) {
  painter.save();

  painter.drawImage(QRect(115, -60, 8, 16), QImage("://images/temperature-icon.png"));

  painter.translate(-160, 100);

  static QColor normal_color(26, 245, 245, 245);
  static QColor overrun_color(245, 64, 64, 225);

  // 绘制表盘外檐
  painter.save();
  painter.setPen(QPen(normal_color, 1, Qt::SolidLine));
  QRect rect(-300, -300, 600, 600);
  painter.drawArc(rect, 12 * 16, 20 * 16);
  painter.restore();

  // 绘制刻度
  painter.save();
  painter.setPen(QPen(normal_color, 1, Qt::SolidLine));
  painter.rotate(-12);
  painter.drawLine(300, 0, 306, 0);
  painter.rotate(-10);
  painter.drawLine(300, 0, 304, 0);
  painter.rotate(-10);
  painter.drawLine(300, 0, 306, 0);
  painter.restore();

  // 绘制刻度值
  painter.save();
  painter.setPen(normal_color);
  painter.setFont(QFont("DejaVu Sans", 6));

  painter.rotate(-12);
  painter.save();
  painter.translate(316, 0);
  painter.rotate(12);
  painter.drawText(QRect(-20, -10, 40, 20), Qt::AlignCenter, QString::number(0) + "°C");
  painter.restore();

  painter.rotate(-10);
  painter.save();
  painter.translate(317, 0);
  painter.rotate(22);
  painter.drawText(QRect(-20, -10, 40, 20), Qt::AlignCenter, QString::number(50) + "°C");
  painter.restore();

  painter.rotate(-10);
  painter.save();
  painter.translate(320, 0);
  painter.rotate(32);
  painter.drawText(QRect(-20, -10, 40, 20), Qt::AlignCenter, QString::number(100) + "°C");
  painter.restore();

  painter.restore();

  // 绘制红色区域
  painter.save();
  static QRectF rectangle_outer(-304, -304, 608, 608);
  static QRectF rectangle_inner(-300.5, -300.5, 601, 601);
  painter.setBrush(overrun_color);
  QPainterPath path;
  path.arcTo(rectangle_outer, 28, 3.9);
  path.arcTo(rectangle_inner, 31.9, -3.9);
  painter.drawPath(path);
  painter.restore();

  // 绘制指针
  painter.save();
  painter.setPen(QPen(overrun_color, 1, Qt::SolidLine));
  painter.rotate(-12 - 0.2 * _temperature);
  painter.drawLine(298, 0, 306, 0);
  painter.restore();

  painter.restore();
}

void FrArmaturenbrett::draw_oil_meter(QPainter& painter) {
  painter.save();

  painter.drawImage(QRect(-130, -60, 16, 16), QImage("://images/fuel-icon.png"));

  painter.translate(160, 100);
  painter.rotate(180);

  static QColor normal_color(26, 245, 245, 245);
  static QColor overrun_color(245, 64, 64, 225);

  // 绘制表盘外檐
  painter.save();
  painter.setPen(QPen(normal_color, 1,  Qt::SolidLine));
  QRect rect(-300, -300, 600, 600);
  painter.drawArc(rect, -12 * 16, -20 * 16);
  painter.restore();

  // 绘制刻度
  painter.save();
  painter.setPen(QPen(normal_color, 1,  Qt::SolidLine));
  painter.rotate(12);
  painter.drawLine(300, 0, 306, 0);
  painter.rotate(10);
  painter.drawLine(300, 0, 304, 0);
  painter.rotate(10);
  painter.drawLine(300, 0, 306, 0);
  painter.restore();

  // 绘制刻度值
  painter.save();
  painter.setPen(normal_color);
  painter.setFont(QFont("DejaVu Sans", 6));

  painter.rotate(12);
  painter.save();
  painter.translate(316, 0);
  painter.rotate(168);
  painter.drawText(QRect(-20, -10, 40, 20), Qt::AlignCenter, QString::number(0) + "%");
  painter.restore();

  painter.rotate(10);
  painter.save();
  painter.translate(317, 0);
  painter.rotate(158);
  painter.drawText(QRect(-20, -10, 40, 20), Qt::AlignCenter, QString::number(50) + "%");
  painter.restore();

  painter.rotate(10);
  painter.save();
  painter.translate(320, 0);
  painter.rotate(148);
  painter.drawText(QRect(-20, -10, 40, 20), Qt::AlignCenter, QString::number(100) + "%");
  painter.restore();

  painter.restore();

  // 绘制红色区域
  painter.save();
  static QRectF rectangle_outer(-304, -304, 608, 608);
  static QRectF rectangle_inner(-300.5, -300.5, 601, 601);
  painter.setBrush(overrun_color);
  QPainterPath path;
  path.arcTo(rectangle_outer, -12.1, -3.9);
  path.arcTo(rectangle_inner, -16, 3.9);
  painter.drawPath(path);
  painter.restore();

  // 绘制指针
  painter.save();
  painter.setPen(QPen(overrun_color, 1, Qt::SolidLine));
  painter.rotate(12 + 0.2 * _oil);
  painter.drawLine(298, 0, 306, 0);
  painter.restore();

  painter.restore();
}

效果图

在这里插入图片描述

  • 9
    点赞
  • 86
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值