简介
本文介绍一种绘制仪表盘的方法,整个仪表盘均采用绘制的方式实现,可自由伸缩大小。
本案例还加入了一个里程表,但是里程表不支持放大和缩小。
这里写图片描述
实现原理
绘制共分为边框、刻度、数字、数字速度(可选)、指针这几部分组成,后绘制的部分会覆盖之前绘制的部分。
共有以下几个要点需要注意:
1、整个页面的是相对大小为200*200,为了保证拉伸窗口时表盘随之拉伸或压缩,需要对坐标系统进行缩放;
painter.scale(scale/m_refSize,scale/m_refSize);
2、将坐标原点设置在表盘中心可以方便对各元素位置的计算;
painter.translate(m_refSize/2,m_refSize/2);
3、绘制表盘刻度数字的时候,需要注意坐标系的Y轴正方向向下,需要在Y值坐标前面添加负号;
绘制函数如下:void paintEvent(QPaintEvent */event/)
paintEvent()是一个父类中的虚函数,函数会在任何页面需要重绘的时候被自动调用,来绘制窗口。所有带有自定义内容的窗口都必须重新实现该函数。使用QPainter进行自定义绘制只能在paintEvent()函数或paintEvent()调用的函数中进行。
可以手动调用update()或者repaint()函数来立刻通知系统调用paintEvent()函数,但是通常update()能获得更好的显示效果,因为它允许Qt进行速度优化和最小的闪烁。
void MainWindow::paintEvent(QPaintEvent */event/)
{
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
float scale = qMin(width(),height());
//设置缩放比例和原点的先后顺序很重要
painter.scale(scale/m_refSize,scale/m_refSize);
painter.translate(m_refSize/2,m_refSize/2); //设置坐标原点
drawFrame(painter); //绘制边框
drawDividing(painter);//绘制刻度
drawNumberIndicator(painter);//绘制指示数字
drawNumberSpeed(painter);//显示数字速度
drawIndicator(painter);//绘制速度指针
// QPoint pos = m_wgt_mileage->mapFromParent(QPoint(-m_wgt_mileage->width()/2,40));
m_wgt_mileage->setGeometry((width() - m_wgt_mileage->width()) / 2 + 30,height() - m_wgt_mileage->height() - 60,m_wgt_mileage->width(),m_wgt_mileage->height());
}
边框绘制 drawFrame(QPainter &painter)
将画笔设置为Qt::NoPen 可以去掉边框外围的边界线,否则会有一圈黑色的轮廓。
这里绘制两个圆,互相重叠,形成一个圆环,同时使用了渐变。
void MainWindow::drawFrame(QPainter &painter)
{
painter.save();
painter.setPen(Qt::NoPen);//确保没有边框线----填满,不留边界线
QLinearGradient lg1(-m_radius,-m_radius,m_radius,m_radius);//渐变区域
lg1.setColorAt(0.1,Qt::white);
lg1.setColorAt(1,Qt::black);
// lg1.setSpread(QGradient::ReflectSpread);//渐变样式
painter.setBrush(lg1);
painter.drawEllipse(-m_radius,-m_radius,m_refSize,m_refSize);
painter.setBrush(Qt::black);
painter.drawEllipse(QPoint(0,0),90,90);
painter.restore();
}
绘制数字 drawNumberIndicator(QPainter &painter)
每隔20KM/H绘制一个标示;
//绘制数字指示
void MainWindow::drawNumberIndicator(QPainter &painter)
{
painter.save();
painter.setPen(Qt::white);
double x,y;
double angle, angleArc;
double w,h;
QFontMetricsF fm(this->font());
for (int i = m_minSpeed; i <= m_maxSpeed; i+= 20)//每隔20Km设置一个数字
{
angle = 360 - (m_startAngle + (i - m_minSpeed) * m_anglePerVel); //角度
angleArc = angle * 3.14 / 180; //转换为弧度
x = 65 * cos(angleArc);//65是一个不断调整后得出的值,不用太在意
y = -65 * sin(angleArc); // 负号的意义在于 Y轴正方向向下
QString speed = QString::number(i);
if (i % 20 == 0)
{
w = fm.width(speed);
h = fm.height();
painter.drawText(QPointF(x - w / 2,y + h/4),speed);
}
}
painter.restore();
}
绘制刻度 drawDividing(QPainter &painter)
//绘制刻度
void MainWindow::drawDividing(QPainter &painter)
{
painter.save();
painter.rotate(m_startAngle);//将坐标系顺时针旋转150°,到达起始位置
QPen pen(Qt::white);
painter.setPen(pen);
int step = (m_maxSpeed - m_minSpeed) / 5;
double angleStep = (360.0 - (m_startAngle - m_endAngle)) / step;
for (int i = m_minSpeed; i <= m_maxSpeed; i += 5)
{
if (i >= 140){ //绘制红色
pen.setColor(Qt::red);
painter.setPen(pen);
}
if (i % 20 == 0){//粗线
pen.setWidth(2);
painter.setPen(pen);
painter.drawLine(88,0,75,0);
}else if (i % 10 == 0){//中等
pen.setWidth(1);
painter.setPen(pen);
painter.drawLine(88,0,80,0);
}else if (i % 5 == 0){ //短线
pen.setWidth(0);
painter.setPen(pen);
painter.drawLine(83,0,80,0);
}
painter.rotate(angleStep);
}
painter.restore();
}
绘制数字式速度 drawNumberSpeed(QPainter &painter)
void MainWindow::drawNumberSpeed(QPainter &painter)
{
painter.save();
painter.setPen(Qt::white);
QString speed = QString("%1 KM/H").arg(m_curSpeed);
QFontMetricsF fm(this->font());
qreal w = fm.size(Qt::TextSingleLine,speed).width();
painter.drawText(-w/2,-20,speed);
painter.restore();
}
绘制指针 drawIndicator(QPainter &painter)
这里根据当前速度计算当前指针的角度,然后旋转坐标系到当前角度。最后绘制指针和旋转中心。
void MainWindow::drawIndicator(QPainter &painter)
{
painter.save();
//绘制指针
double curAngle = m_startAngle + m_curSpeed * m_anglePerVel;
painter.rotate(curAngle); //旋转坐标系
QRadialGradient haloGradient(0, 0, 60, 0, 0); //辐射渐变
haloGradient.setColorAt(0, QColor(60,60,60));
haloGradient.setColorAt(1, QColor(160,160,160)); //灰
painter.setPen(Qt::white); //定义线条文本颜色 设置线条的颜色
painter.setBrush(haloGradient);//刷子定义形状如何填满 填充后的颜色
static const QPointF points[3] = {
QPointF(0.0, 2),
QPointF(0.0, -2),
QPointF(70.0, 0),
};
painter.drawPolygon(points,3); //绘制指针
painter.restore();
painter.save();
//绘制旋转中心
QRadialGradient rg(0,0,10);
rg.setColorAt(0.0,Qt::darkGray);
rg.setColorAt(0.5,Qt::white);
rg.setColorAt(1.0,Qt::darkGray);
painter.setPen(Qt::NoPen);
painter.setBrush(rg);
painter.drawEllipse(QPoint(0,0),5,5);
painter.restore();
}