文章目录
- 1 效果
- 2 原理
- 3 编码实践
- 3.1 创建仪表属性类
- 3.2 设置类属性
- 3.3 绘制图案
- 3.3.1 设置反走样
- 3.3.2 绘制背景
- 3.3.3 重新定义坐标原点
- 3.3.4 绘制圆环
- 3.3.5 绘制刻度线
- 3.3.6 绘制刻度线上的描述值
- 3.3.7 绘制指针
- 3.3.8 绘制指针数值和单位
- 3.3.9 控制指针变化
- 扩展
- 福利
- 参考
1 效果
下面仪表模拟的是转速表和速度表,转速表中有怠速转速,降功转速的逻辑。
下面是模拟双针仪表的效果:
2 原理
1,重写paintEvent
进行仪表绘制,使用QPropertyAnimation
进行动画绘制;
2,进行属性动画绘制时,需要使用Q_PROPERTY宏
用于声明类的属性;
3 编码实践
下面代码位调用方法,接口的具体实现在后文中有详细描述。
发射的信号:
//发送发动机转速
void sendEngineSpeed(double);
//发送大机速度值
void sendTrainSpeedNum(short);
创建仪表类并设置参数:
//发动机转速表
DashBoardWidget3 *dashBoardWidget5 = new DashBoardWidget3(this);
dashBoardWidget5->setScaleMajor(6);//6个大区间
dashBoardWidget5->setScaleMinor(5);//每个区间5个小格
dashBoardWidget5->setUnit("");
dashBoardWidget5->setText("RPMx100");
dashBoardWidget5->setmax(30);
dashBoardWidget5->setUnitDrawInterval(1);//每隔一个大区间画一个刻度线描述值
dashBoardWidget5->setGeometry(750, 20, 300, 300);
connect(this, &MainInterface::sendEngineSpeed,
dashBoardWidget5, &DashBoardWidget3::valueChanged);
//汽车速度表
DashBoardWidget3 *dashBoardWidget6 = new DashBoardWidget3(this);
dashBoardWidget6->setScaleMajor(12);//大区间
dashBoardWidget6->setScaleMinor(2);//每个区间的小值
dashBoardWidget6->setUnit("");
dashBoardWidget6->setText("km/h");
dashBoardWidget6->setmax(120);
dashBoardWidget6->setUnitDrawInterval(2);
// dashBoardWidget->move(600, 20);
dashBoardWidget6->setGeometry(750, 300, 300, 300);
connect(this, &MainInterface::sendTrainSpeedNum,
dashBoardWidget6, &DashBoardWidget3::valueChanged);
3.1 创建仪表属性类
struct DashBoardWidgetPrivate{
//刻度值的最大值和最小值
int maxValue = 100;
int minValue = 0;
//刻度值角度
double startAngle = -50;
double endAngle = 230;
double value = minValue;
//大区间,最小区间
int scaleMajor = 10;
int scaleMinor = 5;
//单位和描述文字
QString unit = "";
QString text = "";
//仪表颜色
QColor arcColor = QColor(56, 61, 74);//QColor(0, 128, 255);
//刻度颜色
QColor scaleColor = QColor(71, 186, 252);//QColor(4, 168, 173);
//指针颜色
QColor pointerColor = QColor(255, 0, 0);
//文件颜色
QColor textColor = QColor(144, 133, 116);
//背景颜色
QColor backgroundColor = Qt::transparent;
//仪表指针1:属性动画
QPropertyAnimation *animation;
};
3.2 设置类属性
Q_PROPERTY(double value READ value WRITE setValue)
Q_PROPERTY(double min READ min WRITE setMin)
Q_PROPERTY(double max READ max WRITE setmax)
Q_PROPERTY(double startAngle READ startAngle WRITE setStartAngle)
Q_PROPERTY(double endAngle READ endAngle WRITE setEndAngle)
Q_PROPERTY(int scaleMajor READ scaleMajor WRITE setScaleMajor)
Q_PROPERTY(int scaleMinor READ scaleMinor WRITE setScaleMinor)
Q_PROPERTY(QString unit READ unit WRITE setUnit)
Q_PROPERTY(QString text READ text WRITE setText)
Q_PROPERTY(QColor arcColor READ arcColor WRITE setArcColor)
Q_PROPERTY(QColor scaleColor READ scaleColor WRITE setScaleColor)
Q_PROPERTY(QColor pointerColor READ pointerColor WRITE setPointerColor)
Q_PROPERTY(QColor textColor READ textColor WRITE setTextColor)
Q_PROPERTY(QColor backgroundColor READ backgroundColor WRITE setBackgroundColor)
创建对应的函数:
QSize sizeHint() const override;
QSize minimumSizeHint() const override;
double value() const;
void setValue(const double value);
void setMin(const double min);
double min() const;
void setmax(const double max);
double max() const;
void setStartAngle(const double startAngle);
double startAngle() const;
void setEndAngle(const double endAngle);
double endAngle() const;
void setScaleMajor(const int scale);
int scaleMajor() const;
void setScaleMinor(const int scale);
int scaleMinor() const;
void setUnit(const QString &unit);//设置单位
QString unit() const;
void setText(const QString &text);//设置文字
QString text() const;
void setArcColor(const QColor &color);
QColor arcColor() const;
void setScaleColor(const QColor &color);
QColor scaleColor() const;
void setPointerColor(const QColor &color);
QColor pointerColor() const;
void setTextColor(const QColor &color);
QColor textColor() const;
void setBackgroundColor(const QColor &color);
QColor backgroundColor() const;
3.3 绘制图案
在类绘制事件中,添加各种绘制信息:
void DashBoardWidget3::paintEvent(QPaintEvent *event){
QWidget::paintEvent(event);
QPainter painter(this);
//....
}
3.3.1 设置反走样
//反走样是图形学中的重要概念,用以防止通常所说的“锯齿”现象的出现。很多系统的绘图 API 里面都内置了有关反走样的算法,不过由于性能问题,默认一般是关闭的
painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
3.3.2 绘制背景
// 背景
if (d->backgroundColor != Qt::transparent) {
painter.setPen(Qt::NoPen);
painter.fillRect(rect(), d->backgroundColor);
}
3.3.3 重新定义坐标原点
// 平移中心
painter.translate(width() / 2, height() / 2);
调整之前:
调整之后:
3.3.4 绘制圆环
// 圆环
drawArc(&painter);
实现函数:
void DashBoardWidget3::drawArc(QPainter *painter)
{
double min = qMin(width(), height());
double arcWidth = min / 15.0;
double radius = min / 3 - arcWidth;
QRectF rect = QRectF(-radius, -radius, radius * 2, radius * 2);
QPen pen;
pen.setWidthF(arcWidth);
pen.setCapStyle(Qt::FlatCap);
// 圆弧背景
double angle = d->endAngle - d->startAngle;
pen.setColor(d->arcColor);
painter->setPen(pen);
painter->drawArc(rect, d->startAngle * 16, angle * 16);
}
绘制效果如下:
3.3.5 绘制刻度线
// 刻度线
drawScale(&painter);
实现函数:
void DashBoardWidget3::drawScale(QPainter *painter)
{
painter->save();
painter->rotate(270 - d->endAngle);
int steps = (d->scaleMajor * d->scaleMinor);//区间*每个区间的小刻度
double angleStep = (d->endAngle - d->startAngle) / steps;
double min = qMin(width(), height());
double radius = min / 3;
QPen pen(d->scaleColor);
pen.setCapStyle(Qt::RoundCap);
for (int i = 0; i <= steps; i++) {
if (i % d->scaleMinor == 0) {//画大刻度
pen.setWidthF(1.5);
painter->setPen(pen);
painter->drawLine(0, radius - 8, 0, radius + 5);//画刻度线长度
}
else
{//画小刻度
pen.setWidthF(0.5);
painter->setPen(pen);
painter->drawLine(0, radius - 8, 0, radius - 3);
}
painter->rotate(angleStep);
}
painter->restore();
}
效果如下:
3.3.6 绘制刻度线上的描述值
// 刻度线上的描述值
drawScaleNum(&painter);
实现函数:
//画刻度线上的说明值
void DashBoardWidget3::drawScaleNum(QPainter *painter)
{
painter->save();
painter->setPen(d->scaleColor);
double min = qMin(width(), height());
double radius = min / 2.4;//半径
QFont font("Microsoft YaHei", min / 25);
painter->setFont(font);
double startRad = d->endAngle * (M_PI / 180);
//qDebug()<<"startRad:"<<startRad;
double deltaRad = (d->endAngle - d->startAngle) * (M_PI / 180) / d->scaleMajor;
QFontMetrics fontMetrics(font);
if(m_unitDrawInterval > d->scaleMajor){
m_unitDrawInterval = d->scaleMajor;
}
for (int i = 0; i <= d->scaleMajor; i += m_unitDrawInterval) {//每个大区间都要画刻度值
double sina = qSin(startRad - i * deltaRad);
double cosa = qCos(startRad - i * deltaRad);
double value = 1.0 * i * ((d->maxValue - d->minValue) / d->scaleMajor) + d->minValue;
// 1.0 * 1 *((1200 -0)/10) + 0
// qDebug()<<"d->maxValue:"<<d->maxValue;
//qDebug()<<"d->minValue:"<<d->minValue;
//qDebug()<<"value:"<<value;
QString strValue = QString("%1").arg(value);
double textWidth = fontMetrics.horizontalAdvance(strValue);
double textHeight = fontMetrics.height();
int x = radius * cosa - textWidth / 2;
int y = -radius * sina + textHeight / 4;
painter->drawText(x, y, strValue);
}
painter->restore();
}
效果如下:
3.3.7 绘制指针
// 指示器(指针)
drawPointer(&painter);
实现函数:
//画指针
void DashBoardWidget3::drawPointer(QPainter *painter)
{
painter->save();
painter->setPen(Qt::NoPen);
painter->setBrush(d->pointerColor);//设置画笔颜色
double radius = qMin(width(), height()) / 3.0;
QPolygonF pts;
pts << QPointF(-5, 0) << QPointF(0, -8)
<< QPointF(5, 0) << QPointF(0, radius);
painter->rotate(270 - d->endAngle);
double degRotate = (d->endAngle - d->startAngle) / (d->maxValue - d->minValue) * (d->value - d->minValue);
painter->rotate(degRotate);
painter->drawConvexPolygon(pts);
painter->restore();
}
效果如下:
3.3.8 绘制指针数值和单位
// 显示指针数值和单位
drawValue(&painter);
实现函数:
//画数值和单位
void DashBoardWidget3::drawValue(QPainter *painter)
{
painter->save();
painter->setPen(d->textColor);
double min = qMin(width(), height());
double radius = min / 2.0 - min / 4.8;
QFont font("Microsoft YaHei", min / 25);
painter->setFont(font);
//绘制指针数值和单位
QString strValue = QString("%1 %2").arg(d->value).arg(d->unit);
QRectF valueRect(-radius, radius / 2.5, radius * 2, radius / 3.5);
QColor pointerColor = QColor(0, 0, 0);
painter->setBrush(pointerColor);
//设置颜色
painter->setPen(QPen(QColor(0, 0, 0)));
painter->drawText(valueRect, Qt::AlignCenter, strValue);
//绘制描述文字
QRectF text2Rect(-radius, radius / 1.5, radius * 2, radius / 2.5);
painter->setPen(QPen(QColor(255, 0, 0)));//设置画笔颜色
painter->setBrush(d->textColor);//设置画笔颜色
font.setPixelSize(12);
painter->setFont(font);
painter->drawText(text2Rect, Qt::AlignCenter, d->text);
painter->restore();
}
实现效果:
3.3.9 控制指针变化
signals:
void valueChanged(const double value);
DashBoardWidget3::DashBoardWidget3(QWidget *parent)
: QWidget(parent)
, d(new DashBoardWidgetPrivate)
{
d->animation = new QPropertyAnimation(this, "value", this);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
connect(this, &DashBoardWidget3::valueChanged,
this, &DashBoardWidget3::onStartAnimation);
}
实现函数:
//仪表指针变动的动画
void DashBoardWidget3::onStartAnimation(double value)
{
if(value < d->minValue
|| value > d->maxValue
|| value == d->value){
}else{
double start = d->value;
double end = value;
d->animation->setStartValue(start);
d->animation->setEndValue(end);
d->animation->start();
}
}
扩展
可以思考以下,下面的效果如何实现?
福利
完整的项目代码
欢迎各位start
参考
Qt自定义控件之仪表盘的完整实现