cpp
复制代码
#include "widget.h"
#include <QPainter>
#include <QtMath>
#include <QDebug>
#include <QPainterPath>
QRect getEllipseRect(const QPoint ¢er, int rx, int ry)
{
return QRect(center.x() - rx, center.y() - ry, 2 * rx, 2 * ry);
}
struct Graphical_DashboardPrivate
{
int maximumValue{100};
int maximumScaleValue{280};
int startAngle;
int endAngle;
bool semiCircle{0};//是否半圆
QColor backgroundColor{"#ff000000"};
QColor borderGradient_topLeftColor{"#ffffffff"};
QColor borderGradient_bottomRightColor{"#ff000000"};
QColor scaleColor{"#ffffffff"};
QColor scaleValueColor{"#ffffffff"};
QColor pointerBorderColor{"#ffffffff"};
QColor pointerbackgroundColor{"#ffA0A0A0"};
QColor centralWheelGradient_insideColor{"#ff808080"};
QColor centralWheelGradient_outsideColor{"#ffffffff"};
int pointerBorderWidth{3};
int centralWheelRadius{26};
qreal anglePerVel;
void calculateClockwiseRange();
void drawFrame(QPainter &painter);
void drawScale(QPainter &painter);
void drawScaleReadings(QPainter &painter);
void drawPointer(QPainter &painter);
};
void Graphical_DashboardPrivate::calculateClockwiseRange()
{
if(maximumScaleValue >= 180)
{
startAngle = (360 - maximumScaleValue) / 2 + 90; // 计算起始角度,转换为顺时针角度
endAngle = (startAngle + maximumScaleValue) % 360; // 计算结束角度,转换为顺时针角度
anglePerVel = (360.0 - (startAngle - endAngle)) / maximumScaleValue;
}
else
{
startAngle = 270 - (maximumScaleValue/2);
endAngle = startAngle + maximumScaleValue;
anglePerVel = (endAngle - startAngle) / maximumScaleValue;
}
}
//边框
void Graphical_DashboardPrivate::drawFrame(QPainter &painter)
{
//500 = radius
static QPoint origin{0,0};
painter.save();
painter.setPen(Qt::transparent);
QLinearGradient lg(-500,-500,500,500);
lg.setColorAt(0,borderGradient_topLeftColor);
lg.setColorAt(1,borderGradient_bottomRightColor);
painter.setBrush(lg);
if(semiCircle)
{
auto rect = getEllipseRect(origin,500,500);
int newHeight = rect.height() / 2;
rect.setHeight(newHeight + 50);
painter.setClipRect(rect);
}
painter.drawEllipse(origin,480,480);
auto rect = getEllipseRect(origin,430,430);
QPainterPath path;
path.addEllipse(rect);
painter.setClipPath(path);
if(semiCircle)
{
int newHeight = rect.height() / 2;
rect.setHeight(newHeight+12);
}
painter.fillRect(rect,backgroundColor);
painter.restore();
}
//刻度
void Graphical_DashboardPrivate::drawScale(QPainter &painter)
{
painter.save();
painter.rotate(startAngle);//将坐标系顺时针旋转150°,到达起始位置
int step = maximumScaleValue / 5;
float angleStep;
if(maximumScaleValue >= 180)
{
angleStep = (360.0 - (startAngle - endAngle)) / step;
}
else
{
angleStep = (endAngle - startAngle) / step;
}
for (int i = 0; i <= maximumScaleValue; i += 5)
{
if (i % 20 == 0)//粗线
{
painter.setPen(QPen(scaleColor,10));
painter.drawLine(420, 0, 340, 0);
}
else if (i % 10 == 0)//中等
{
painter.setPen(QPen(scaleColor,6));
painter.drawLine(420, 0, 380, 0);
}
else if (i % 5 == 0)//短线
{
painter.setPen(QPen(scaleColor,4));
painter.drawLine(400, 0, 380, 0);
}
painter.rotate(angleStep);
}
painter.restore();
}
//刻度值
void Graphical_DashboardPrivate::drawScaleReadings(QPainter &painter)
{
painter.save();
painter.setPen(scaleValueColor);
qreal x,y,w,h,angle,angleArc;
auto font = painter.font();
font.setPixelSize(45);
painter.setFont(font);
QFontMetricsF fm(font);
for (int i = 0; i <= maximumScaleValue; i+= 20)
{
if (i % 20 == 0)
{
angle = 360 - (startAngle + i * anglePerVel); //角度
angleArc = angle * 3.14 / 180; //转换为弧度
x = 280 * cos(angleArc);
y = -280 * sin(angleArc); // 负号的意义在于 Y轴正方向向下
QString speed = QString::number(i * maximumValue/maximumScaleValue);
w = fm.width(speed);
h = fm.height();
painter.drawText(QPointF(x - w / 2,y + h/4),speed);
}
}
painter.restore();
}
//绘制指针
void Graphical_DashboardPrivate::drawPointer(QPainter &painter)
{
painter.save();
int currentValue = maximumScaleValue/2;
float curAngle = startAngle + currentValue * anglePerVel;
painter.rotate(curAngle); //旋转坐标系
QRadialGradient haloGradient(0, 0, 60, 0, 0); //辐射渐变
haloGradient.setColorAt(0, pointerbackgroundColor.darker());
haloGradient.setColorAt(1, pointerbackgroundColor);
if(pointerBorderWidth == 0)
{
painter.setPen(Qt::transparent);
}
else
{
painter.setPen(QPen(pointerBorderColor,pointerBorderWidth));
}
painter.setBrush(haloGradient);
const QPointF points[3]
{
QPointF(0.0, centralWheelRadius/2),
QPointF(0.0, -centralWheelRadius/2),
QPointF(300.0, 0),
};
painter.drawPolygon(points,3); //绘制指针
painter.restore();
painter.save();
//绘制旋转中心
QRadialGradient rg(0,0,40);
rg.setColorAt(0.0,centralWheelGradient_insideColor);
rg.setColorAt(0.5,centralWheelGradient_outsideColor);
rg.setColorAt(1.0,centralWheelGradient_insideColor);
painter.setPen(Qt::NoPen);
painter.setBrush(rg);
painter.drawEllipse(QPoint(0,0),centralWheelRadius,centralWheelRadius);
painter.restore();
}
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
setPalette(QPalette(QPalette::Background,Qt::white));
d_ptr = new Graphical_DashboardPrivate;
d_ptr->calculateClockwiseRange();
}
Widget::~Widget()
{
}
void Widget::paintEvent(QPaintEvent *event)
{
auto thisRect = rect();
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
painter.setRenderHints(QPainter::TextAntialiasing);
painter.setRenderHints(QPainter::SmoothPixmapTransform);
int side;
if(d_ptr->semiCircle)
{
side = qMin(thisRect.width(), thisRect.height()*2);
side = qMin(thisRect.width(), thisRect.height()*2 - (side/20) * 2);
painter.translate(thisRect.width() / 2, thisRect.height() - side /20 );
}
else
{
side = qMin(thisRect.width(), thisRect.height());
painter.translate(thisRect.width() / 2, thisRect.height() / 2);
}
painter.scale(side / 1000.0, side / 1000.0);
d_ptr->drawFrame(painter);
d_ptr->drawScale(painter);
d_ptr->drawScaleReadings(painter);
d_ptr->drawPointer(painter);
}