最近学习了一下QT,熟悉了一段时间后发现它的功能还是挺强大的,同时也比较方便用户上手去使用。现在就基于最近学习的内容,实现一个简易的带指针旋转功能的表盘。文中表盘的实现是基于QT的QPainter类中的绘图方法,同时外加QT的定时器设计完成的。效果上肯定没有贴图片那么美观,不过两者的设计思想是基本一样的,这里的设计方法可以提供给你一个不错的参考。
(资料图片仅供参考)
在讲解设计思路前还是先来看下绘制的表盘所实现的效果吧!后面对实现效果进行一步步拆解来讲解,这样或许会更加直观,更便于理解。
我们先不去考虑指针旋转这一动态过程实现,可以将表盘分解析为3个组成部分,表盘的外形轮廓、指针和显示的当前速度的数值。外形轮廓由一个圆弧和一些指示刻度组成,它的绘制肯定要使用QT中的画圆弧的函数、画线函数还有显示文本函数。指针是一个不规则的多边形,它的绘制会用到QT中的绘制多边形的函数。显示当前速度值比较简单些,直接使用显示文本函数绘制。
有了静态部分的基础,现在开始考虑指针的动态旋转过程和旋转过程中的渐变效果是如何实现的。指针旋转的角度应该和当前的转速相互对应,当前转速改变时,会根据新的转速计算出当前指针位于什么角度的位置,然后可以调用QT的旋转角度函数让多边形指针旋转到这个位置。旋转的渐变效果其实是通过绘制扇形实现的,要绘制扇形的角度和指针旋转的角度是一样,由于绘制的扇形的内部的着色采用了颜色的线性内插,所以不同的角度显示的颜色程度不同,因此给人以渐变的效果。
转速的周期改变是在定时器中完成的,构造函数中初始化一个周期定时器,当定时器时间超时,根据当前转速的状态(上行还是下行),确定让转速自增1还是自减1。转速改变时,调用函数让界面进行重新绘制。
所用到的绘制函数都是QPainter类中的方法, QPainter可以理解成是个画家,这个画家有很多种绘制图形的方法,它可以在所有继承QPaintDevice的类上进行绘制。
绘制多边形:
drawPolygon
QT中drawPolygon有很多重载版本,要传入的参数一般就是要指定绘制多边形的所有顶点位置。
绘制圆弧:
drawArc
同理,QT中也有很多drawArc的重载版本。它传入的参数比较特殊,QT中的绘制圆弧是在一个正方形中操作的,要传入的是正方形区域的大小,绘制圆弧的圆心默认是在传入正方形区域中心。除此之外还需要指定要绘制圆弧的起始角度和跨越的角度,它传入是值是实际角度*16。 当传入的角度值为正,表示逆时针绘制圆弧,角度值为负,表示顺时钟绘制圆弧。
绘制扇形:
drawPie
绘制扇形和绘制圆弧的参数类似,可参考绘制圆弧。
QPainter坐标转换:
translate
如执行painter.translate(100, 100),后续绘制的参考坐标变成了相对100, 100位置而言的。执行painter.drawLine(0, 0, 0, 20),实际绘制直线的两端点是(100, 100)和(100, 120)
旋转:
ratate
坐标转换和旋转过程可参考下图:
保存和恢复QPainter状态:
save
restore
save保存当前QPainter状态(即当前对QPainter的设置)到堆栈,restore恢复之前保存的状态。这两个方法在QPainter绘图中很有用,详细可参考后面代码。
先从定时器函数函数来看,当构造函数中设置的定时器超时,会产生定时器事件,timerEvent被自动调用
void Widget::timerEvent(QTimerEvent *e){int timerId = e->timerId();if(this->time_id == timerId) {if(this->status == 0) {this->speed += 1;if(this->speed >= 180)this->status = 1;}else {this->speed -= 1;if(this->speed <= 0)this->status = 0;}this->update();}}
判断当前转速是处于上行还是下行状态,根据转速所处的状态修改转速。然后调用this->update(), 该函数会产生Widget类中的重绘事件,paintEvent函数被执行。
painteEvent函数内容如下:
void Widget::paintEvent(QPaintEvent *event){qreal angle;angle = (qreal)270 / (180-1);QPainter painter(this);painter.translate(width()/2, height()/2);drawFrame(&painter, angle); //①drawPointer(&painter, angle); //②drawSpeed(&painter); //③}
① 绘制仪表盘圆弧形状的外框
② 根据转速大小,计算当前指针所在的角度,然后绘制指针和产生渐变效果的扇形
③ 显示当前转速值
drawFrame函数
void Widget::drawFrame(QPainter *painter, qreal angle){painter->save();painter->setBrush(QBrush(QColor(0, 255, 0, 255), Qt::SolidPattern));painter->drawArc(-200, -200, 400, 400, -135*16, -270*16); //①painter->restore();for(int i = 0; i < 180; i++) { //②painter->save();painter->rotate(-225 + i * angle);if(i % 10 == 0) {painter->drawLine(180, 0, 200, 0);}else {painter->drawLine(190, 0, 200, 0);}painter->restore();}painter->save();for(int i = 0; i < 9; i++) { //③int xTextPos = 180 * qCos((225 - i * 15)*3.14/180);int yTextPos = -180 * qSin((225 - i * 15)*3.14/180);painter->drawText(xTextPos+5, yTextPos+10, QString::number(i * 10));painter->drawText(-xTextPos-25, yTextPos+10, QString::number((18 - i) * 10));}painter->drawText(-10, -165, \"90\");painter->restore();}
① 绘制表盘的外形圆弧
② 绘制圆弧上的刻度信息
③ 绘制表盘外形的刻度旁边的数值,这里利用了圆的对称性
drawPointer函数void Widget::drawPointer(QPainter *painter, qreal angle){QPoint point[4] = {QPoint(0, 10),QPoint(-10, 0),QPoint(0, -170),QPoint(10, 0),};painter->save();QLinearGradient linear; //①linear.setStart(-200, -200);linear.setFinalStop(200, 200);linear.setColorAt(0, QColor(0, 255, 255, 0));linear.setColorAt(1, QColor(0, 255, 255, 255));painter->setPen(Qt::NoPen);painter->setBrush(linear);painter->drawPie(-200, -200, 400, 400, 225 * 16, -(angle * this->speed) * 16);painter->restore();painter->save();painter->setBrush(QBrush(QColor(0, 0, 0, 255), Qt::SolidPattern));painter->rotate(-135 + this->speed * angle);painter->drawPolygon(point, 4); //②painter->restore();}
① 根据当前速度计算扇形区域的大小,绘制渐变扇形
② 根据当前速度计算指针所要在的位置,旋转指针到该位置
drawSpeed函数void Widget::drawSpeed(QPainter *painter){painter->save();painter->setPen(QColor(\"#0\"));// 绘制速度QFont font(\"Times\", 10, QFont::Bold);font.setBold(true);font.setPixelSize(66);painter->setFont(font);painter->drawText(-60, 100, 120, 92, Qt::AlignCenter, QString::number(speed));painter->restore();}
drawSpeed函数在指定位置,使用指定颜色字体,显示当前速度
5、小结
到此,模拟仪表盘的实现讲解完毕了,这也算对这几天QT的学习做了一个小小的总结。从使用过程中可以感受到使用QT进行图形界面的设计,软件编写上还是比较灵活的。QT的GUI功能非常很强大,它提供的接口函数很多,但想要都用好的确很难,平时还需要多看看QT官方文档中的解释和提供的demo。
完整代码
#include \"widget.h\"#include #include #include #include #include #include #include Widget::Widget(QWidget *parent): QWidget(parent){resize(800, 480);setWindowTitle(\"模拟仪表盘\");this->speed = 0;this->status = 0;this->time_id = this->startTimer(50);}Widget::~Widget(){}void Widget::paintEvent(QPaintEvent *event){qreal angle;angle = (qreal)270 / (180-1);QPainter painter(this);painter.translate(width()/2, height()/2);drawFrame(&painter, angle);drawPointer(&painter, angle);drawSpeed(&painter);}void Widget::drawFrame(QPainter *painter, qreal angle){painter->save();painter->setBrush(QBrush(QColor(0, 255, 0, 255), Qt::SolidPattern));painter->drawArc(-200, -200, 400, 400, -135*16, -270*16);painter->restore();for(int i = 0; i < 180; i++) {painter->save();painter->rotate(-225 + i * angle);if(i % 10 == 0) {painter->drawLine(180, 0, 200, 0);}else {painter->drawLine(190, 0, 200, 0);}painter->restore();}painter->save();for(int i = 0; i < 9; i++) {int xTextPos = 180 * qCos((225 - i * 15)*3.14/180);int yTextPos = -180 * qSin((225 - i * 15)*3.14/180);painter->drawText(xTextPos+5, yTextPos+10, QString::number(i * 10));painter->drawText(-xTextPos-25, yTextPos+10, QString::number((18 - i) * 10));}painter->drawText(-10, -165, \"90\");painter->restore();}void Widget::drawPointer(QPainter *painter, qreal angle){QPoint point[4] = {QPoint(0, 10),QPoint(-10, 0),QPoint(0, -170),QPoint(10, 0),};painter->save();QLinearGradient linear;linear.setStart(-200, -200);linear.setFinalStop(200, 200);linear.setColorAt(0, QColor(0, 255, 255, 0));linear.setColorAt(1, QColor(0, 255, 255, 255));painter->setPen(Qt::NoPen);painter->setBrush(linear);painter->drawPie(-200, -200, 400, 400, 225 * 16, -(angle * this->speed) * 16);painter->restore();painter->save();painter->setBrush(QBrush(QColor(0, 0, 0, 255), Qt::SolidPattern));painter->rotate(-135 + this->speed * angle);painter->drawPolygon(point, 4);painter->restore();}void Widget::drawSpeed(QPainter *painter){painter->save();painter->setPen(QColor(\"#0\"));// 绘制速度QFont font(\"Times\", 10, QFont::Bold);font.setBold(true);font.setPixelSize(66);painter->setFont(font);painter->drawText(-60, 100, 120, 92, Qt::AlignCenter, QString::number(speed));painter->restore();}void Widget::timerEvent(QTimerEvent *e){int timerId = e->timerId();if(this->time_id == timerId) {if(this->status == 0) {this->speed += 1;if(this->speed >= 180)this->status = 1;}else {this->speed -= 1;if(this->speed <= 0)this->status = 0;}this->update();}}
widget.cpp
#ifndef WIDGET_H#define WIDGET_H#include class Widget : public QWidget{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();void paintEvent(QPaintEvent *event);void timerEvent(QTimerEvent *e);private:void drawFrame(QPainter *painter, qreal angle);void drawPointer(QPainter *painter, qreal angle);void drawSpeed(QPainter *painter);int speed;int time_id;int status;};#endif // WIDGET_Hwidegt.h
main.cpp
#include \"widget.h\"#include int main(int argc, char *argv[]){QApplication a(argc, argv);Widget w;w.show();return a.exec();}main.cpp
【领 QT开发教程 学习资料, 点击下方链接莬费领取↓↓ ,先码住不迷路~】
点击这里:
上一篇:国能龙岩发电:“三抓三促”确保安全生产持续稳定-当前时讯
下一篇:最后一页
1、简介最近学习了一下QT,熟悉了一段时间后发现它的功能还是挺强大的,同时也比较方便用户上手去使用。现
为确保班组管理工作的高效规范运行,今年来,国能龙岩发电公司立足工作实际,以落实标准化制度为核心,通过
1、怀调还叫怀梆,是一个古老稀有、独具乡土特色的民间地方剧种,其历史悠久,流行面甚广,曾是广大群众喜
云创数据近期接受投资者调研时表示,在国产化方面,公司已经与国内多家国产化平台实现了兼容性互认证,包括
马英九:大陆立刻停止派军机在台周边活动,不希望台成第二个香港,香港,大陆,军机,蔡英文,民进党,骑士团,科
外交部:愿同澳方共同推动双边关系行稳致远、中澳合作持久深化:据媒体,5月18日,外交部发言人汪文斌主持
图源:摄图网喜茶于5月17日在全国近1000家门店门店上线了名为“FENDI喜悦黄”的联名饮品,其明黄色纸杯的正
中国青年网合肥5月18日电(记者侯倩倩)初夏的安徽马鞍山薛家洼生态园鸟语花香、绿树成荫,一江碧水荡漾着
淄博新闻网讯(全媒体记者赵晓雯通讯员单峰)5月17日,2023“中国品牌日”(山东)活动在日照市举办,活动
金投黄金网5月18日讯,郑州黄金价格_郑州六福今天黄金价格是多少(每日更新)