C++ QT 自绘表盘

文章目录

效果图

代码

  • 代码没什么好说的,直接上源码
  • .h
cpp 复制代码
#pragma once

#include <QWidget>
#include <QPainter>
#include <QResizeEvent>
#include <QtMath>
#include <QCoreApplication>

class DialPlateWidget : public QWidget
{
    Q_OBJECT
    Q_PROPERTY(double minValue READ getMinValue WRITE setMinValue USER true)
    Q_PROPERTY(double maxValue READ getMaxValue WRITE setMaxValue USER true)
    Q_PROPERTY(double value READ getValue WRITE setValue USER true)

public:
    explicit DialPlateWidget(QWidget *parent = nullptr);
    // 获取和设置最小值
    double getMinValue() const;
    void setMinValue(double minValue);
    // 获取和设置最大值
    double getMaxValue() const;
    void setMaxValue(double maxValue);
    /// @brief  设置当前值
    void setValue(double ivalue);
    double getValue() const;
    /// @brief 设置标题和单位
    /// @param title
    /// @param unit
    void setContent(QString title, QString unit = QString());

    QSize sizeHint() const override;
    QSize minimumSizeHint() const override;
    ~DialPlateWidget();

private:
    void paintEvent(QPaintEvent *event) override;

    void drawBg(QPainter *painter);
    void drawDial(QPainter *painter);
    void drawScaleNum(QPainter *painter);
    void drawIndicator(QPainter *painter);
    void drawText(QPainter *painter);

private:
    QString unit;            // 单位
    QString title;           // 名称
    const static int radius; // 半径
    double maxv;             // 最小值
    double minv;             // 最大值
    double percent = 0;      // 百分比
    int m_refSize = 200;     // 刻度线长度
    int Angle = 45;          // 刻度线角度
    double m_value = 0;      // 当前值
};
  • cpp
cpp 复制代码
#include "dialPlateWidget.h"

const int DialPlateWidget::radius = 100;

DialPlateWidget::DialPlateWidget(QWidget *parent) : QWidget(parent)
{
    maxv = 200;
    minv = 0;
    this->installEventFilter(this);
    m_refSize = 2.5 * radius;
}

DialPlateWidget::~DialPlateWidget()
{
}

void DialPlateWidget::setValue(double ivalue)
{
    // 确保值在最小值和最大值之间
    if (ivalue < minv)
    {
        ivalue = minv;
    }
    else if (ivalue > maxv)
    {
        ivalue = maxv;
    }
    m_value = ivalue;
    percent = (ivalue - minv) / (maxv - minv) * 100;
    update();
}

double DialPlateWidget::getValue() const
{
    return minv + percent * (maxv - minv) / 100; // 根据百分比计算实际值
}

QSize DialPlateWidget::sizeHint() const
{
    return QSize(m_refSize, m_refSize);
}

QSize DialPlateWidget::minimumSizeHint() const
{
    return QSize(30, 10);
}

void DialPlateWidget::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);

    // 计算缩放比例,确保仪表盘适应Widget大小
    float scale = qMin(width(), height()) / (float)m_refSize;
    painter.scale(scale, scale);

    // 设置坐标原点为中心点
    painter.translate(width() / (2 * scale), height() / (2 * scale));

    // 绘制背景、刻度线、刻度数字、指针和文字
    drawBg(&painter);
    drawDial(&painter);
    drawScaleNum(&painter);
    drawIndicator(&painter);
    drawText(&painter);

    QWidget::paintEvent(event);
}

void DialPlateWidget::drawBg(QPainter *painter)
{
    int r = radius;
    painter->save();
    painter->setPen(Qt::NoPen);
    painter->setBrush(QColor(172, 172, 172));
    painter->drawEllipse(-r, -r, r * 2, r * 2);

    r = radius * 0.9;
    painter->setBrush(QColor(40, 40, 40));
    painter->setPen(Qt::NoPen);
    painter->drawEllipse(-r, -r, r * 2, r * 2);
    painter->restore();
}

void DialPlateWidget::drawDial(QPainter *painter)
{
    int r = radius * 0.85;
    double lineWidth = 1;
    painter->save();

    painter->rotate(Angle);

    double rotate = (double)(360 - (Angle * 2)) / 100;

    for (int i = 0; i <= 100; i++)
    {
        QColor color = QColor(84, 84, 84);
        if (i <= 30)
            color = QColor(250, 0, 0);
        if (i > 30)
            color = QColor(0, 255, 0, 255);
        if ((i % 10) == 0)
        {
            painter->setPen(QPen(color, 4.2 * lineWidth));
            painter->drawLine(0, r, 0, r / 1.2);
        }
        else if ((i % 2) == 0)
        {
            painter->setPen(QPen(color, 1 * lineWidth));
            painter->drawLine(0, r, 0, r / 1.1);
        }
        painter->rotate(rotate);
    }

    painter->restore();
}

void DialPlateWidget::drawScaleNum(QPainter *painter)
{
    painter->save();

    int r = (int)(radius * 0.6); // 增加半径,使刻度数字更远离中心
    painter->setFont(QFont("Arial", 12));
    painter->setPen(QPen(QColor(255, 255, 255)));
    QFontMetricsF fm = QFontMetricsF(painter->font());

    // 计算五个标值的间隔
    double valueRange = maxv - minv;
    double valueStep = valueRange / 4.0;          // 四个间隔,五个标值
    double angleStep = (360.0 - Angle * 2) / 4.0; // 对应的角度间隔

    for (int i = 0; i <= 4; ++i)
    {
        double value = minv + i * valueStep;       // 当前标值
        double angle = 90 + Angle + i * angleStep; // 当前标值对应的角度

        float angleArc = (int(angle) % 360) * 3.14 / 180; // 转换为弧度
        int x = r * cos(angleArc);
        int y = r * sin(angleArc);

        QString speed = QString::number(value);
        int w = (int)fm.width(speed);
        int h = (int)fm.height();
        x = x - w / 2;
        y = y + h / 4; // 调整文本位置

        painter->drawText(QPointF(x, y), speed);
    }

    painter->restore();
}

void DialPlateWidget::drawIndicator(QPainter *painter)
{
    painter->save();
    QPolygon pts;
    int r = radius * 0.6;
    pts.setPoints(3, -2, 0, 2, 0, 0, r);

    double angle = Angle + (360.0 - 2 * Angle) * (percent / 100.0);

    painter->rotate(angle);

    // 绘制指针
    QRadialGradient haloGradient(0, 0, 60, 0, 0); // 辐射渐变,内部填充颜色
    haloGradient.setColorAt(0, QColor(100, 100, 100));
    haloGradient.setColorAt(1, QColor(250, 50, 50)); // red
    painter->setPen(QColor(250, 150, 150));          // 边框颜色
    painter->setBrush(haloGradient);
    painter->drawConvexPolygon(pts);

    // 绘制中心圆圈
    QRadialGradient radial(0, 0, 14); // 渐变
    radial.setColorAt(0.0, QColor(100, 100, 100));
    radial.setColorAt(1.0, QColor(250, 50, 50));
    painter->setPen(Qt::NoPen); // 填满没有边界
    painter->setBrush(radial);
    painter->drawEllipse(-7, -7, 14, 14);

    painter->restore();
}

void DialPlateWidget::drawText(QPainter *painter)
{
    painter->save();

    painter->setFont(QFont("Arial", 8));
    painter->setPen(QPen(QColor(255, 255, 255)));
    QFontMetricsF fm = QFontMetricsF(painter->font());
    QString speed = title + QString::number(m_value) + unit;
    int w = (int)fm.width(speed);
    painter->drawText(QPointF(-w / 2, (int)(0.7 * radius)), speed);
    painter->restore();
}

void DialPlateWidget::setContent(QString title, QString unit)
{
    this->unit = unit;
    this->title = title;
    update(); // 更新显示
}

double DialPlateWidget::getMinValue() const
{
    return minv;
}

void DialPlateWidget::setMinValue(double minValue)
{
    minv = minValue;
}

double DialPlateWidget::getMaxValue() const
{
    return maxv;
}

void DialPlateWidget::setMaxValue(double maxValue)
{
    maxv = maxValue;
}
相关推荐
叶孤程14 分钟前
Qt图形化界面为何总被“冷落“?
开发语言·c++·qt
葵野寺20 分钟前
【多线程】线程池
java·开发语言·java-ee·web app
写代码写到手抽筋30 分钟前
C++多线程的性能优化
java·c++·性能优化
二进制人工智能32 分钟前
【QT5 网络编程示例】UDP 通信
c++·qt
高林雨露33 分钟前
Java 与 Kotlin 对比学习指南(二)
java·开发语言·kotlin
Maple_land33 分钟前
# C++初阶——内存管理
c++
笑口常开xpr35 分钟前
C 语 言 --- 整 形 提 升
c语言·开发语言
予安灵43 分钟前
第十二届蓝桥杯省赛软件类(c&c++组)
c语言·c++·蓝桥杯
martian6651 小时前
Maven核心配置文件深度解析:pom.xml完全指南
java·开发语言
小白狮ww1 小时前
Retinex 算法 + MATLAB 软件,高效率完成图像去雾处理
开发语言·人工智能·算法·matlab·自然语言处理·图像识别·去雾处理