Qt学习优化的一款汽车仪表控件,根据github上面开源的进行优化,主要使用QPainter实现的一款炫酷仪表盘,其中的渐变效果比较有感觉
实现结果
仪表盘

实现源码
h文件
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QPixmap>
#include <QTimer>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
protected:
void paintEvent(QPaintEvent *event) override;
void resizeEvent(QResizeEvent *event) override;
private:
Ui::Widget *ui;
QTimer *timer;
QPixmap cachedBackground;
bool backgroundDirty;
// 仪表盘参数
const int MAX_SPEED = 240; // 最大速度
const int START_ANGLE = 150; // 起始角度
const int ANGLE_SPAN = 240; // 角度跨度
const int WARNING_THRESHOLD = 40; // 警告阈值(刻度值)
int currentValue; // 当前值(0-60)
int mark; // 标记递增或递减
double angle; // 每个刻度角度
void startSpeed();
void initCanvas(QPainter& painter);
void drawMiddleCircle(QPainter &painter, int radius);
void drawCurrentSpeed(QPainter &painter);
void drawScale(QPainter &painter, int radius);
void drawScaleText(QPainter &painter, int radius);
void drawPointLine(QPainter &painter, int length);
void drawSpeedArc(QPainter &painter, int radius);
void drawEllipseInnerBlack(QPainter &painter, int radius);
void drawEllipseInnerGlow(QPainter &painter, int radius);
void drawOuterRing(QPainter &painter, int radius);
void drawLogo(QPainter &painter, int radius);
void drawTechCircles(QPainter &painter, int radius);
void drawWarningEffect(QPainter &painter, int radius);
};
#endif // WIDGET_H
c文件
#include "widget.h"
#include "ui_widget.h"
#include <QPainter>
#include <QTimer>
#include <QtMath>
#include <QEasingCurve>
#include <QResizeEvent>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
, backgroundDirty(true)
{
ui->setupUi(this);
setFixedSize(800, 600);
mark = 0;
currentValue = 0;
angle = ANGLE_SPAN * 1.0 / (MAX_SPEED / 4); // 计算每个刻度角度
startSpeed();
}
Widget::~Widget()
{
delete ui;
}
void Widget::startSpeed()
{
timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, [=](){
if (mark == 0) {
currentValue = qMin(currentValue + 1, MAX_SPEED/4);
mark = (currentValue >= MAX_SPEED/4) ? 1 : 0;
} else {
currentValue = qMax(currentValue - 1, 0);
mark = (currentValue == 0) ? 0 : 1;
}
// 当接近警告阈值时刷新效果
if (currentValue >= WARNING_THRESHOLD - 5 && currentValue <= WARNING_THRESHOLD + 5) {
backgroundDirty = true;
}
update();
});
timer->start(50);
}
void Widget::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
// 只在需要时重绘背景
if (backgroundDirty) {
cachedBackground = QPixmap(size());
cachedBackground.fill(Qt::transparent);
QPainter bgPainter(&cachedBackground);
int radius = height()/2;
initCanvas(bgPainter);
drawOuterRing(bgPainter, radius+25);
drawScale(bgPainter, radius);
drawScaleText(bgPainter, radius);
drawTechCircles(bgPainter, radius);
drawLogo(bgPainter, radius);
backgroundDirty = false;
}
painter.drawPixmap(0, 0, cachedBackground);
// 只绘制动态部分
int radius = height()/2;
painter.translate(rect().width()/2, rect().height()*0.6);
drawSpeedArc(painter, radius+25);
drawEllipseInnerGlow(painter, 110);
drawEllipseInnerBlack(painter, 80);
drawMiddleCircle(painter, 60);
drawCurrentSpeed(painter);
drawPointLine(painter, radius-58);
// 警告效果
if (currentValue >= WARNING_THRESHOLD) {
drawWarningEffect(painter, radius+25);
}
}
void Widget::resizeEvent(QResizeEvent *event)
{
backgroundDirty = true;
QWidget::resizeEvent(event);
}
void Widget::initCanvas(QPainter& painter)
{
painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform | QPainter::TextAntialiasing);
// 科技感深色背景
QLinearGradient gradient(0, 0, width(), height());
gradient.setColorAt(0, QColor(10, 15, 30));
gradient.setColorAt(1, QColor(5, 10, 20));
painter.setBrush(gradient);
painter.drawRect(rect());
// 坐标系平移到坐标中心
QPoint cent(rect().width()/2, rect().height()*0.6);
painter.translate(cent);
}
void Widget::drawMiddleCircle(QPainter &painter, int radius)
{
painter.setPen(QPen(QColor(100, 180, 255), 3));
painter.setBrush(QColor(20, 30, 50));
painter.drawEllipse(QPoint(0, 0), radius, radius);
// 中心小圆点
painter.setPen(Qt::NoPen);
painter.setBrush(QColor(100, 180, 255));
painter.drawEllipse(QPoint(0, 0), 5, 5);
}
void Widget::drawCurrentSpeed(QPainter &painter)
{
// 主速度值
QFont font("Arial", 30);
font.setBold(true);
painter.setFont(font);
// 文字发光效果
QLinearGradient textGradient(0, -60, 0, -20);
textGradient.setColorAt(0, QColor(150, 220, 255));
textGradient.setColorAt(1, QColor(50, 150, 255));
painter.setPen(QPen(textGradient, 1));
painter.drawText(QRect(-60, -60, 120, 70), Qt::AlignCenter, QString::number(currentValue*4));
// 单位
QFont font2("Arial", 13);
font2.setBold(true);
painter.setFont(font2);
painter.setPen(QColor(150, 200, 255));
painter.drawText(QRect(-60, -60, 120, 160), Qt::AlignCenter, "Km/h");
}
void Widget::drawScale(QPainter &painter, int radius)
{
painter.save();
painter.rotate(START_ANGLE);
for (int i = 0; i <= MAX_SPEED/4; i++) {
// 设置不同颜色
if (i >= WARNING_THRESHOLD) {
painter.setPen(QPen(QColor(255, 80, 80), 5));
} else {
painter.setPen(QPen(QColor(100, 180, 255), 5));
}
if (i % 5 == 0) {
// 长刻度线
painter.drawLine(radius - 20, 0, radius - 3, 0);
} else {
// 短刻度线
painter.drawLine(radius - 8, 0, radius - 3, 0);
}
painter.rotate(angle);
}
painter.restore();
}
void Widget::drawScaleText(QPainter &painter, int radius)
{
QFont font("Arial", 15);
font.setBold(true);
painter.setFont(font);
int r = radius - 49;
for (int i = 0; i <= MAX_SPEED/4; i++) {
if (i % 5 == 0) {
painter.save();
// 计算文本位置
double textAngle = 210 - angle * i;
int delX = qCos(qDegreesToRadians(textAngle)) * r;
int delY = qSin(qDegreesToRadians(textAngle)) * r;
painter.translate(QPoint(delX, -delY));
painter.rotate(-120 + angle * i);
// 设置文本颜色
if (i >= WARNING_THRESHOLD) {
painter.setPen(QColor(255, 100, 100));
} else {
QLinearGradient grad(0, 0, 0, 20);
grad.setColorAt(0, QColor(150, 220, 255));
grad.setColorAt(1, QColor(50, 150, 255));
painter.setPen(QPen(grad, 1));
}
painter.drawText(-25, -25, 50, 30, Qt::AlignCenter, QString::number(i*4));
painter.restore();
}
}
}
void Widget::drawPointLine(QPainter &painter, int length)
{
painter.save();
// 指针渐变
QLinearGradient gradient(0, 0, length, 0);
if (currentValue >= WARNING_THRESHOLD) {
gradient.setColorAt(0, QColor(255, 150, 150));
gradient.setColorAt(0.5, QColor(255, 100, 100));
gradient.setColorAt(1, QColor(200, 50, 50));
} else {
gradient.setColorAt(0, QColor(200, 230, 255));
gradient.setColorAt(0.5, QColor(100, 180, 255));
gradient.setColorAt(1, QColor(50, 120, 220));
}
painter.setBrush(gradient);
painter.setPen(Qt::NoPen);
// 指针形状
QPainterPath path;
path.moveTo(0, 0);
path.lineTo(length * 0.9, -length * 0.02);
path.lineTo(length, 0);
path.lineTo(length * 0.9, length * 0.02);
path.closeSubpath();
// 旋转并绘制指针
painter.rotate(START_ANGLE + angle * currentValue);
painter.drawPath(path);
// 指针中心圆
painter.setBrush(QColor(30, 50, 80));
painter.drawEllipse(QPoint(0, 0), 10, 10);
// 中心圆发光效果
QRadialGradient centerGrad(0, 0, 10);
centerGrad.setColorAt(0, QColor(100, 180, 255, 150));
centerGrad.setColorAt(1, Qt::transparent);
painter.setBrush(centerGrad);
painter.drawEllipse(QPoint(0, 0), 15, 15);
painter.restore();
}
void Widget::drawSpeedArc(QPainter &painter, int radius)
{
QRect rectangle(-radius, -radius, radius*2, radius*2);
painter.setPen(Qt::NoPen);
// 速度弧渐变
QConicalGradient gradient(0, 0, -START_ANGLE);
gradient.setColorAt(0.0, QColor(100, 200, 255, 200));
gradient.setColorAt(0.5, QColor(50, 150, 255, 150));
gradient.setColorAt(1.0, QColor(0, 100, 200, 100));
painter.setBrush(gradient);
painter.drawPie(rectangle, (360-START_ANGLE)*16, -angle*currentValue*16);
// 添加发光效果
QRadialGradient glow(0, 0, radius);
glow.setColorAt(0, QColor(100, 180, 255, 50));
glow.setColorAt(1, Qt::transparent);
painter.setBrush(glow);
painter.drawPie(rectangle, (360-START_ANGLE)*16, -angle*currentValue*16);
}
void Widget::drawEllipseInnerBlack(QPainter &painter, int radius)
{
painter.setBrush(QColor(20, 30, 50));
painter.setPen(Qt::NoPen);
painter.drawEllipse(QPoint(0, 0), radius, radius);
}
void Widget::drawEllipseInnerGlow(QPainter &painter, int radius)
{
QRadialGradient gradient(0, 0, radius);
gradient.setColorAt(0.0, QColor(100, 180, 255, 150));
gradient.setColorAt(0.5, QColor(50, 120, 220, 100));
gradient.setColorAt(1.0, QColor(0, 50, 100, 50));
painter.setBrush(gradient);
painter.setPen(Qt::NoPen);
painter.drawEllipse(QPoint(0, 0), radius, radius);
}
void Widget::drawOuterRing(QPainter &painter, int radius)
{
QRect rectangle(-radius, -radius, radius*2, radius*2);
painter.setPen(Qt::NoPen);
// 外环渐变
QRadialGradient gradient(0, 0, radius);
gradient.setColorAt(1.0, QColor(50, 150, 255, 150));
gradient.setColorAt(0.97, QColor(50, 150, 255, 50));
gradient.setColorAt(0.9, Qt::transparent);
gradient.setColorAt(0, Qt::transparent);
painter.setBrush(gradient);
painter.drawPie(rectangle, (360-START_ANGLE)*16, -angle*(MAX_SPEED/4)*16);
// 外环边缘
painter.setPen(QPen(QColor(100, 180, 255, 100), 2));
painter.setBrush(Qt::NoBrush);
painter.drawArc(rectangle, (360-START_ANGLE)*16, -angle*(MAX_SPEED/4)*16);
}
void Widget::drawLogo(QPainter &painter, int radius)
{
QRect rectangle(-65, radius*0.38, 130, 50);
// 绘制logo背景
painter.setPen(QPen(QColor(100, 180, 255, 100), 1));
painter.setBrush(QColor(0, 0, 0, 100));
painter.drawRoundedRect(rectangle, 5, 5);
// 绘制logo图片
painter.drawPixmap(rectangle, QPixmap(":/icon.png"));
}
void Widget::drawTechCircles(QPainter &painter, int radius)
{
// 绘制科技感同心圆
painter.setPen(QPen(QColor(50, 150, 255, 30), 1));
painter.setBrush(Qt::NoBrush);
for (int i = 1; i <= 5; i++) {
int r = radius * 0.2 * i;
painter.drawEllipse(QPoint(0, 0), r, r);
}
// 绘制径向线
for (int i = 0; i < 360; i += 15) {
painter.save();
painter.rotate(i);
painter.drawLine(QPoint(0, 0), QPoint(radius, 0));
painter.restore();
}
}
void Widget::drawWarningEffect(QPainter &painter, int radius)
{
static int alpha = 0;
static bool increasing = true;
// 更新alpha值
if (increasing) {
alpha += 10;
if (alpha >= 80) increasing = false;
} else {
alpha -= 10;
if (alpha <= 20) increasing = true;
}
// 绘制蓝色闪烁效果
painter.setPen(Qt::NoPen);
painter.setBrush(QColor(100, 150, 255, alpha));
painter.drawEllipse(QPoint(0, 0), radius, radius);
}
希望对大家有所帮助