Qt炫酷仪表盘

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);
}

希望对大家有所帮助

相关推荐
noravinsc1 小时前
python提升图片清晰度
开发语言·python
假女吖☌1 小时前
Maven 编译指定模版
java·开发语言·maven
水w4 小时前
【Python爬虫】简单案例介绍1
开发语言·爬虫·python
qq_365911606 小时前
GPT-4、Grok 3与Gemini 2.0 Pro:三大AI模型的语气、风格与能力深度对比
开发语言
Susea&7 小时前
数据结构初阶:队列
c语言·开发语言·数据结构
慕容静漪7 小时前
如何本地安装Python Flask并结合内网穿透实现远程开发
开发语言·后端·golang
ErizJ7 小时前
Golang|锁相关
开发语言·后端·golang
GOTXX7 小时前
【Qt】Qt Creator开发基础:项目创建、界面解析与核心概念入门
开发语言·数据库·c++·qt·图形渲染·图形化界面·qt新手入门
搬砖工程师Cola7 小时前
<C#>在 .NET 开发中,依赖注入, 注册一个接口的多个实现
开发语言·c#·.net
巨龙之路8 小时前
Lua中的元表
java·开发语言·lua