Qt实现简易仪表盘

效果如下,仪表盘部分paintevent绘制

主要代码

复制代码
头文件
#ifndef XDWGTPOINTER_H
#define XDWGTPOINTER_H

#include <QWidget>
#include <QPainter>
#include <VBF_BarTitle.h>
class XdWgtPointer : public QWidget
{
    Q_OBJECT
public:
    explicit XdWgtPointer(QWidget *parent = nullptr);

    // 设置角度接口,角度范围0-180
    void setAngle(int angle);

protected:
    void paintEvent(QPaintEvent *event) override;
    void resizeEvent(QResizeEvent *event) override;

private:
    // 计算颜色渐变(0-180对应绿到红)
    QColor getGradientColor(int angle);

    // 绘制圆弧刻度线和刻度值
    void drawScale(QPainter &painter);

    // 绘制简化指针
    void drawPointer(QPainter &painter);

private:
    int m_angle;               // 传入的角度(0-180)
    int m_rotationAngle;       // 实际旋转角度(180 - m_angle)
    QRectF m_drawingArea;      // 整体绘图区域
    qreal m_arcRadius;         // 圆弧刻度半径
    QPointF m_center;          // 旋转中心(指针和刻度的共同中心)
    const int m_scaleCount = 19; // 刻度数量(0-180,每10度一个)
    const int m_valueStep = 30;  // 刻度值间隔(每30度显示一个值)

    //标题栏
    CVBF_BarTitle m_Title;
};

#endif // XDWGTPOINTER_H

#include "XdWgtPointer.h"
#include "XdUtils.h"
#include <QResizeEvent>
#include <QtMath>
#include <QHBoxLayout>
#include <QApplication>

XdWgtPointer::XdWgtPointer(QWidget *parent)
    : QWidget(parent)
    , m_angle(0)
    , m_rotationAngle(0) // 初始水平向左
{
    setMinimumSize(300, 250);

    QHBoxLayout* layout = new QHBoxLayout(this);
    QWidget* w = new QWidget();
    layout->addWidget(w);
    layout->setMargin(0);

    setAttribute(Qt::WA_TranslucentBackground);
    setWindowFlags(Qt::FramelessWindowHint);

    show();hide();
    int margin = 35;
    m_Title.setGeometry(0,0,this->width(),margin);
    m_Title.setObjectName("TitleBar");
    m_Title.setParent(this);
    m_Title.SetTitle(QStringLiteral("角度"));
    QPixmap pix = qApp->windowIcon().pixmap(25,25);
    // m_Title.SetIcon(pix);
    m_Title.SetIcoRect(0,0,1,1);
    m_Title.SetTitleRect(10,5,100,30);
    m_Title.initBtn(CVBF_BarTitle::CLOSE_BTN);

}

void XdWgtPointer::setAngle(int angle)
{
    angle = qBound(0, angle, 180);

    if (m_angle != angle)
    {
        m_angle = angle;
        m_rotationAngle = m_angle;
        update();
    }
}

void XdWgtPointer::resizeEvent(QResizeEvent *event)
{
    Q_UNUSED(event);

    // 1. 计算整体居中的绘图区域
    int margin = 15;
    int maxWidth = width() - margin * 2;
    int maxHeight = height() - margin * 2;
    int contentSize = qMin(maxWidth, maxHeight); // 取宽高中的较小值作为基准

    // 确保绘图区域在窗口正中心
    m_drawingArea = QRectF(
        (width() - contentSize) / 2.0,    // 水平居中
        (height() - contentSize) / 2.0,   // 垂直居中
        contentSize,
        contentSize
        );

    // 2. 调整旋转中心(上移至绘图区域中上部,避免圆弧向下延伸)
    m_center = QPointF(
        m_drawingArea.center().x(),
        m_drawingArea.top() + contentSize * 0.8 // 中心y坐标:从顶部向下60%位置(上移)
        );

    // 3. 圆弧半径(控制在绘图区域上半部分,避免下方出现多余圆弧)
    m_arcRadius = contentSize * 0.4; // 半径为内容区的40%
}

QColor XdWgtPointer::getGradientColor(int angle)
{
    qreal ratio = angle / 180.0;
    int red = qMin(255, (int)(ratio * 240));
    int green = qMin(255, (int)((1 - ratio) * 200));
    int blue = qMin(150, (int)(100 + ratio * 50));
    return QColor(red, green, blue);
}

void XdWgtPointer::drawScale(QPainter &painter)
{
    painter.save();
    painter.setRenderHint(QPainter::Antialiasing);

    // 绘制圆弧基线(严格180度上半圆,避免下方多余部分)
    painter.setPen(QPen(QColor(80, 90, 100), 2));
    QRectF arcRect(
        m_center.x() - m_arcRadius,
        m_center.y() - m_arcRadius,
        m_arcRadius * 2,
        m_arcRadius * 2
        );
    // 绘制上半圆(180度):起始角度180度(左侧水平),跨度180度(向右到右侧水平)
    //painter.drawArc(arcRect, 180 * 16, 180 * 16); // 角度单位为1/16度

    // 绘制刻度线和刻度值
    painter.setPen(QColor(255, 255, 227));
    QFont font = painter.font();
    font.setPointSize(13);
    painter.setFont(font);

    for (int i = 0; i < m_scaleCount; ++i)
    {
        // 刻度角度范围:180度(左)到0度(右),仅上半圆
        int scaleAngle = 180 - (i * 180) / (m_scaleCount - 1);
        qreal rad = qDegreesToRadians((qreal)scaleAngle);

        // 刻度线起点(圆弧上)和终点(向外延伸)
        qreal startX = m_center.x() + m_arcRadius * qCos(rad);
        qreal startY = m_center.y() - m_arcRadius * qSin(rad); // y轴向下为正,用减号
        qreal endX = m_center.x() + (m_arcRadius + 10) * qCos(rad);
        qreal endY = m_center.y() - (m_arcRadius + 10) * qSin(rad);

        // 主刻度(30度间隔)
        if (i % (m_valueStep / 10) == 0)
        {
            painter.setPen(QPen(QColor(255, 255, 255), 3));
            endX = m_center.x() + (m_arcRadius + 15) * qCos(rad);
            endY = m_center.y() - (m_arcRadius + 15) * qSin(rad);

            // 刻度值
            qreal textX = m_center.x() + (m_arcRadius + 25) * qCos(rad);
            qreal textY = m_center.y() - (m_arcRadius + 25) * qSin(rad);
            QString text = QString::number((i * 180) / (m_scaleCount - 1));
            QRectF textRect(textX - 15, textY - 10, 30, 20);
            painter.drawText(textRect, Qt::AlignCenter, text);
        }
        else
        {
            painter.setPen(QPen(QColor(255, 255, 255), 2));
        }

        painter.drawLine(QPointF(startX, startY), QPointF(endX, endY));
    }

    painter.restore();
}

void XdWgtPointer::drawPointer(QPainter &painter)
{
    painter.save();
    painter.setRenderHint(QPainter::Antialiasing);

    // 旋转中心
    painter.translate(m_center);
    painter.rotate(m_rotationAngle);

    // 简化指针(更纤细的设计)
    qreal pointerLength = m_arcRadius * 0.85;
    qreal tipWidth = 5;
    qreal tailWidth = 3;
    qreal tailLength = 12;

    QPainterPath pointerPath;
    pointerPath.moveTo(-pointerLength, 0);                  // 尖端
    pointerPath.lineTo(tailLength, tipWidth / 2);           // 右上前
    pointerPath.lineTo(tailLength, tailWidth / 2);          // 右后上
    pointerPath.lineTo(0, tailWidth / 2);                   // 尾部上
    pointerPath.lineTo(0, -tailWidth / 2);                  // 尾部下
    pointerPath.lineTo(tailLength, -tailWidth / 2);         // 右后下
    pointerPath.lineTo(tailLength, -tipWidth / 2);          // 右前下
    pointerPath.closeSubpath();

    // 指针颜色
    QColor pointerColor = getGradientColor(m_angle);
    painter.setBrush(pointerColor);
    painter.setPen(QPen(pointerColor.darker(120), 1));
    painter.drawPath(pointerPath);

    // 中心圆
    qreal centerRadius = 6;
    painter.setBrush(QColor(50, 60, 70));
    painter.setPen(QPen(QColor(100, 110, 120), 2));
    painter.drawEllipse(QPointF(0, 0), centerRadius, centerRadius);

    painter.restore();
}

void XdWgtPointer::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event);

    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);

    // 背景
    painter.fillRect(rect(), wsy::getBackoundColor());

    // 绘制刻度和指针
    drawScale(painter);
    drawPointer(painter);
}
cpp 复制代码
//调用
XdWgtPointer* w = new XdWgtPointer();
connect(&timer, &QTimer::timeout, [=]() {
    w->setAngle(qrand() % 180);
});
timer.start(1000);
w->show();

最后附上最近正在更新的QGIS二次开发教程
QGIS二次开教程

相关推荐
Unlyrical1 小时前
为什么moduo库要进行线程检查
linux·服务器·开发语言·c++·unix·muduo
天天摸鱼的小学生1 小时前
【Java Enum枚举】
java·开发语言
崇山峻岭之间1 小时前
C++ Prime Plus 学习笔记028
c++·笔记·学习
阿猿收手吧!1 小时前
【C++】cpp虚函数和纯虚函数的声明和定义
开发语言·c++
q_30238195561 小时前
Python实现基于多模态知识图谱的中医智能辅助诊疗系统:迈向智慧中医的新篇章
开发语言·python·知识图谱
橘颂TA1 小时前
【Linux】System V 通信——共享内存
linux·运维·服务器·c++
梨落秋霜1 小时前
Python入门篇【输入input】
开发语言·python
wen-pan1 小时前
Go 语言 GMP 调度模型深度解析
开发语言·go
Buxxxxxx2 小时前
DAY 34 模块和库的导入
开发语言·python