效果如下,仪表盘部分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二次开教程