Qt自定义汽车速度表控件,支持自适应缩放,效果如下图:
speedBoard.h:
#ifndef SPEED_BOARD_H
#define SPEED_BOARD_H
#include <QWidget>
class Speedboard : public QWidget
{
Q_OBJECT
public: Speedboard(QWidget* parent = nullptr);
void setValue(qreal ivalue);
private:
void paintEvent(QPaintEvent* event) override;
private:
int radius = 80;
int maxv = 100;
int minv = 0;
qreal value;
};
#endif // SPEED_BOARD_H
SpeedBoard.cpp:
#include "speedboard.h"
#include <qpainter.h>
#include <QtMath>
#include <QDateTime>
#include <stdlib.h>
Speedboard::Speedboard(QWidget* parent) :
QWidget(parent)
{
value = 0;
}
void Speedboard::setValue(qreal ivalue)
{
value = ivalue;
update();
}
void Speedboard::paintEvent(QPaintEvent*)
{
radius = qMin(width(), height()) / 2 - 20;
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
QPoint center(width() / 2, height() / 2);
painter.save();
/* 绘制背景圆形 */
painter.translate(center);
painter.setPen(Qt::NoPen);
painter.setBrush(QColor(143, 143, 143));
const int bkRadius = radius + 3;
painter.drawEllipse(QPoint(), bkRadius, bkRadius);
/* 绘制长短刻度线 */
painter.rotate(-135);
const int longStep = 10;
const int shortStep = 50;
for(int i = 0; i <= shortStep; i++)
{
/* 前80%绿色刻度线,后20%红色 */
painter.setPen((i < shortStep * 0.8) ? QColor(32, 243, 32) : QColor(243, 32, 32));
if(i % (shortStep / longStep) != 0)
{
QPoint p1(0, -(radius - 8));
QPoint p2(0, -radius);
painter.drawLine(p1, p2);
}
else
{
QPoint pl(0, -(radius - 12));
QPoint p2(0, -radius);
painter.drawLine(pl, p2);
}
painter.rotate(270.0 / shortStep);
}
/* 绘制表盘名字和它的背景矩形 */
painter.restore();
QFontMetrics fm = painter.fontMetrics();
int tx = center.x();
int ty = int(center.y() + (radius / 1.4142));
QString title = u8"仪表盘";
QSize tsz = fm.size(0, title);
QRect trect(QPoint(tx - tsz.width() / 2, ty - tsz.height() / 2), tsz);
painter.setPen(QColor(127, 127, 127));
painter.setBrush(QColor(173, 163, 163));
painter.drawRoundedRect(trect.adjusted(-6, -4, 6, 4), 3, 3);
painter.setPen(QColor(243, 243, 243));
painter.setBrush(Qt::NoBrush);
painter.drawText(trect, title);/* 绘制每个长刻度线对应的文字 */
painter.setPen(QColor(243, 243, 243));
const int hand = radius - 21;
for(int i = 0; i <= longStep; i++)
{
qreal angle = qDegreesToRadians(-135.0 + i * (270.0 / longStep));
QString etext = QString::number(minv + i * (maxv - minv) / longStep); /* 注意这里整形运算 */
QPointF dirVec(qSin(angle), -qCos(angle));
QPointF ecenter(center.x() + hand * dirVec.x(), center.y() + hand * dirVec.y());
QSize esz = fm.size(0, etext);
QRectF erect(QPointF(ecenter.x() - esz.width() / 2, ecenter.y() - esz.height() / 2), esz);
painter.drawText(erect, etext);
}
/* 绘制表盘指针 */
painter.save();
QPoint triangle[] = /* 向上的三角形 */
{
{ -5, 0 },
{ 0, 25 - radius },
{ 5, 0 },
};
qreal degree = -135.0 + 270.0 * (value - minv) / (maxv - minv);
painter.translate(center);
painter.rotate(degree);
painter.setPen(Qt::NoPen);
painter.setBrush(Qt::red);
painter.drawPolygon(triangle, 3);
painter.setPen(QPen(QColor(213, 0, 0), 2));
painter.drawEllipse(QPoint(), 7, 7);
painter.restore();
}
测试代码main.cpp:
#include "speedboard.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Speedboard w;
w.show();
return a.exec();
}
工程文件speedBoard.pro:
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = SpeedBoard
TEMPLATE = app
SOURCES += \
main.cpp \
speedboard.cpp
HEADERS += \
speedboard.h