Qt自绘汽车仪表盘-1

一、效果图

在这里插入图片描述
二、效果图拆解
根据效果图上显示,最外层一共是13个小点,这些小点有点像子弹头一样,头部是尖的,底部是平的。靠近一层是表盘码值表,数字是的底部朝向表盘圆心。再近一层是一个渐变圆环,颜色有黑色渐变成白蓝色。里面是121个刻度线,最里面是长刻度线和短刻度线,这些刻度线都是头尖底圆。最后内部正上方是绘制的文字,表盘中的指针也是头头尖底圆,指向0值。
其中主题颜色为蓝白色,指针颜色为暗红色。
三、绘制过程拆解
①首先是要解决里面图形(子弹头和数字)旋转的问题,如果直接计算旋转之后的图形再绘制,可能真的比较麻烦,不过三角函数比较优秀的人可以尝试直接旋转图形再绘制。这里采用的方法是使用QPainter自带的旋转绘图坐标的方式,先将坐标旋转之后,绘制图像,再将坐标还原回来,结果图看上去就是绘制的图形被旋转了。
②首先绘制最外层的13个子弹头,这些子弹头不是规则的图形(不是正方形,长方形之类的),但是可以用一个长方形+一个三角形构成,如下图所示:

在这里插入图片描述
这里绘制的是等比例放大的图像,将这个图像缩小之后,看上去菱角不那么明显时,就会误以为是圆角的(实际是眼睛欺骗了大脑的结果,当初为了实现菱角圆滑,真的费了很多心思没结果)。
这个图形虽然可以用正方形+三角形的方式构成,但是在绘图的时候比较麻烦,需要绘制两次,或者可以用QPainterPath计算两个图形的并集,但是都比较麻烦,不如直接用QPainterPath将路径添加在集合中,一次绘制即可。
③绘制13个数字码值表。这里也是先将坐标旋转之后,绘制数字,最后还原坐标。
④绘制渐变圆环。这里没有使用绘制两个扇形圆的方式(内部绘制一个遮罩圆),这里是先将圆环的路径计算出来,然后直接绘制路径所在的区域。
⑤绘制内部121个短刻度线。这里的效果图上看着短刻度线头尖底圆,这里和绘制子弹头相同,实际也是因为眼睛欺骗了大脑,实际这个子弹头放大之后是下面这样的:

在这里插入图片描述
实际上就是两个等腰梯形合并在一起的,由于效果图上点线距离太小,所以看上去就像是圆的。
⑥绘制长短刻度线。绘制方法和上面绘制短刻度线异样,只是梯形的长度不一样。
⑦绘制表盘上的文字。这里和绘制表盘数字一样。
⑧绘制表盘指针。这里由于指针图像比较大,不能再用梯形的方式绘制指针底部,所以这里指针底部是一个半圆。
四、绘制前准备
这里根据效果图表盘一共被分成12个区间,一共13个点,在坐标上,为了计算方便,本文中设置每两个相邻的点之间的度数为20°(圆形是360°),每两个小刻度之间的角度为2°,这样整个表盘的其实角度就是-30°,终点角度为210°,表盘扇形区域总度数为240°。
再说Qt坐标系,Qt坐标系是向右为x轴,右为正,左为负,向下为y轴,下为正,上为负。所以这样表盘的相对Qt坐标系的起始角度为-120°,终点角度为120°。
五、详细绘制过程
①准备工作,先设置对话框窗口大小,设置窗口背景颜色等,代码如下所示:

//设置窗口大小
setFixedSize(640,480);
//去掉问号
Qt::WindowFlags flags= this->windowFlags();
setWindowFlags(flags&~Qt::WindowContextHelpButtonHint);
//背景设置成黑色
QPalette bgpal=palette();
bgpal.setColor(QPalette::Background,QColor(0,0,0));
setPalette(bgpal);

②重载窗口绘图函数,初始化QPainter对象,移动绘图坐标中心,设置窗口画笔画刷等,代码如下所示:

void Dashboard::paintEvent(QPaintEvent*)
{QPainter painter(this);int width=this->width();int height=this->height();int radius=((width>height)?height:width)/2;//将画笔移动到中下方painter.translate(width>>1,height*0.6);//启用反锯齿painter.setRenderHint(QPainter::Antialiasing, true);//取消画笔painter.setPen(Qt::NoPen);//设置画刷颜色painter.setBrush(QColor(98,246,255));
}

当前设置完成后,界面一片纯黑,效果图如下所示:

在这里插入图片描述
③绘制13个子弹头。这里分成几步一步步实现,描述清楚坐标计算、坐标移动等,后续步骤中也会用到,不再进行描述。
A.首先,组装子弹头的效果路径,代码如下所示:

//组装点的路径图
QPainterPath pointPath;
pointPath.moveTo(-2,-2);
pointPath.lineTo(2,-2);
pointPath.lineTo(2,2);
pointPath.lineTo(0,4);
pointPath.lineTo(-2,2);

在Qt坐标系中绘制这个闭合图形,得到的效果图如下所示:

在这里插入图片描述
这里可能会有疑问,为什么moveTo坐标是负数,而不是0。这里这样设置主要是将坐标原点绘制在被绘制图形的中心,这样图形旋转之后,图形的中点还是在坐标的中心点。
B.然后计算这些子弹头的旋转坐标值,以左下角的子弹头为例。根据Qt坐标系计算,这个子弹头的旋转角度是-120°(别问我怎么知道的,这个旋转一下就知道了)。下一个子弹头,旋转角度是在-120°的基础上加上20°,依次类推,就可以绘制出所有子弹头的被旋转的图像。
这里用到了Qt坐标系的旋转,函数是rotate函数,是QPainter下的函数。使用方法如下代码所示:

painter.rotate(-120);

旋转之后的子弹头效果图如下所示:

在这里插入图片描述
C.这里既然绘制出了第一个,那剩下的12个绘制就很方便了,因为旋转角度是逐渐递增的,递增角度为20°。所以旋转代码如下:

painter.rotate(-120+i*20);
绘制13个子弹头的代码如下所示:
for(int i=0;i<13;++i){painter.save();//计算并选择绘图对象坐标painter.rotate(-120+i*20);//绘制路径painter.drawPath(pointPath);painter.restore();
}

这里用到QPainter函数的save函数和restore函数,这两个函数一般是成对出现的,这里是先将绘图对象保存一下,因为后面需要旋转坐标,绘制完成之后,恢复绘图对象,被旋转的坐标自然就被恢复了,不然就需要将坐标旋转回来。
这一步因为所有子弹头的绘制坐标都在中心点,所以所有子弹头都重叠在一起,如下图所示:

在这里插入图片描述
D.将子弹头分开。当前由于坐标系原点在控件中间,要将子弹头绘制在圆环上(意识里的圆环上),就需要计算每一个子弹头的坐标。计算每一个子弹头的坐标代码如下所示:

for(int i=0;i<13;++i){QPointF point(0,0);painter.save();//计算绘图对象中心点point.setX(radius*qCos(((210-i*20)*M_PI)/180));point.setY(radius*qSin(((210-i*20)*M_PI)/180));painter.restore();
}

其中point就是子弹头绘制的坐标。为了方便绘图,直接将绘图坐标的中心点移动到计算出来的坐标点上,代码如下所示:

painter.translate(point.x(),-point.y());

这里为什么y坐标是负数?因为三角函数是基于常规的坐标系计算的(y轴向上为正),而Qt坐标系刚好相反(y轴向下为正),所以这里需要y坐标转换一下。
E.完整的绘制13个子弹头的代码如下:

void Dashboard::DrawPoint(QPainter& painter,int radius)
{//组装点的路径图QPainterPath pointPath;pointPath.moveTo(-2,-2);pointPath.lineTo(2,-2);pointPath.lineTo(2,2);pointPath.lineTo(0,4);pointPath.lineTo(-2,2);//绘制13个小点for(int i=0;i<13;++i){QPointF point(0,0);painter.save();//计算并移动绘图对象中心点point.setX(radius*qCos(((210-i*20)*M_PI)/180));point.setY(radius*qSin(((210-i*20)*M_PI)/180));//计算并移动绘图对象的中心点painter.translate(point.x(),-point.y());//计算并选择绘图对象坐标painter.rotate(-120+i*20);//绘制路径painter.drawPath(pointPath);painter.restore();}
}

效果如下图:

在这里插入图片描述
④绘制表盘数字。坐标旋转移动中心点的方法和③中相同,后续不在详细描述,直接上代码:

void Dashboard::DrawDigital(QPainter& painter,int radius)
{//绘制13个小点for(int i=0;i<13;++i){QPointF point(0,0);painter.save();//计算并移动绘图对象中心点point.setX(radius*qCos(((210-i*20)*M_PI)/180));point.setY(radius*qSin(((210-i*20)*M_PI)/180));//计算并移动绘图对象的中心点painter.translate(point.x(),-point.y());//计算并选择绘图对象坐标painter.rotate(-120+i*20);//绘制路径painter.drawText(-15, 0, 30, 20,Qt::AlignCenter,QString::number(i*20));painter.restore();}
}

效果图如下:

在这里插入图片描述
很惊奇的发现居然什么都没有?对,确实什么都没有,原因是绘制文字,需要设置画笔,在初始化的时候,将画笔去掉了,这里需要设置画笔,代码如下所示:

painter.setPen(QColor(98,246,255));

效果图如下所示:

在这里插入图片描述
界面看上去比较丑陋,那是因为这里字体字号等都是系统默认的,需要自己设置字体,本工程中字体设置为黑体,字号为16,代码如下所示:

QFont font;
font.setFamily("SimHei");
font.setPointSize(16);
painter.setFont(font);

效果图如下所示:

在这里插入图片描述
⑤绘制渐变圆环。这里采用的饭饭是先计算扇形圆弧的扇形区域,再计算内圆(圆环内测圆)的路径,两个路径求差集(路劲差集就是圆环的路径),绘制锥形渐变,外测为黑色,内测为蓝白色,代码如下所示:

void Dashboard::DrawCircle(QPainter& painter,int radius)
{//保存绘图对象painter.save();//计算大小圆路径QPainterPath outRing;QPainterPath inRing;outRing.moveTo(0,0);inRing.moveTo(0,0);outRing.arcTo(-radius,-radius, 2*radius,2*radius,-31,242);inRing.addEllipse(-radius+20,-radius+20,2*(radius-20),2*(radius-20));outRing.closeSubpath();//设置渐变色QRadialGradient radialGradient(0,0,radius,0,0);radialGradient.setColorAt(0.95,QColor(98,246,255));radialGradient.setColorAt(1,QColor(0,0,0));//设置渐变画刷painter.setBrush(radialGradient);//大圆减去小圆得到圆环painter.drawPath(outRing.subtracted(inRing));//恢复绘图对象painter.restore();
}

这里有一个问题需要说明,outRing.arcTo函数中,扇形圆的其实角度应该是-31,结束角度应该是240,但是这里偏移了一点点,是因为后续绘制刻度尺的时候,刻度尺的中心点坐标对应的是-30°和240°,刻度尺有宽度,所以看上去就没有对齐,为了让界面看上去对齐,这里扇形圆做了一定的偏移。
效果图如下所示:

在这里插入图片描述
⑥绘制小刻度尺。这里的每个小刻度的绘制方法和上面子弹头的绘制方法一样,唯一不一样的是小刻度的底部不是平的,有一点点突出,为了实现这个效果,这里处理方法是两个梯形合并在一起。路径代码和绘制代码如下所示:

void Dashboard::DrawSmallScale(QPainter& painter,int radius)
{//组装点的路径图QPainterPath pointPath;pointPath.moveTo(-2,-2);pointPath.lineTo(-1,-4);pointPath.lineTo(1,-4);pointPath.lineTo(2,-2);pointPath.lineTo(1,8);pointPath.lineTo(-1,8);//绘制121个小点for(int i=0;i<121;++i){QPointF point(0,0);painter.save();//计算并移动绘图对象中心点point.setX(radius*qCos(((210-i*2)*M_PI)/180));point.setY(radius*qSin(((210-i*2)*M_PI)/180));//计算并移动绘图对象的中心点painter.translate(point.x(),-point.y());//计算并选择绘图对象坐标painter.rotate(-120+i*2);//绘制路径painter.drawPath(pointPath);painter.restore();}
}

效果图如下所示:

在这里插入图片描述
⑦绘制大刻度。方法和绘制小刻度一样,只是长短刻度需要区分一下。代码如下所示:

void Dashboard::DrawBigScale(QPainter& painter,int radius)
{//组装点的路径图QPainterPath pointPath1;pointPath1.moveTo(-2,-2);pointPath1.lineTo(-1,-4);pointPath1.lineTo(1,-4);pointPath1.lineTo(2,-2);pointPath1.lineTo(1,8);pointPath1.lineTo(-1,8);QPainterPath pointPath2;pointPath2.moveTo(-2,-2);pointPath2.lineTo(-1,-4);pointPath2.lineTo(1,-4);pointPath2.lineTo(2,-2);pointPath2.lineTo(1,15);pointPath2.lineTo(-1,15);//绘制25个刻度for(int i=0;i<25;++i){QPointF point(0,0);painter.save();//计算并移动绘图对象中心点point.setX(radius*qCos(((210-i*10)*M_PI)/180));point.setY(radius*qSin(((210-i*10)*M_PI)/180));//计算并移动绘图对象的中心点painter.translate(point.x(),-point.y());//计算并选择绘图对象坐标painter.rotate(-120+i*10);//绘制路径if(i%2){painter.drawPath(pointPath1);}else{painter.drawPath(pointPath2);}painter.restore();}
}

效果图如下所示:

在这里插入图片描述
⑧绘制表盘上的文字。这里又需要将画笔设置出来。代码如下所示:

void Dashboard::DrawText(QPainter& painter,int radius)
{painter.save();//设置画笔painter.setPen(QColor(98,246,255));//设置字体QFont font;font.setFamily("Microsoft YaHei");font.setPointSize(16);painter.setFont(font);painter.drawText(-25, -radius, 50, 20,Qt::AlignCenter,QString("km/h"));painter.restore();
}

效果图如下所示:

在这里插入图片描述
⑨最后一步是绘制一个指针。废话不多说,直接上代码。如果前面的代码都搞明白了,最后这个指针也就没啥难度了,最可能出问题就是指针底部的半圆路径绘制。

void Dashboard::DrawPointer(QPainter& painter,int radius)
{//组装点的路径图QPainterPath pointPath;pointPath.moveTo(10,0);pointPath.lineTo(1,-radius);pointPath.lineTo(-1,-radius);pointPath.lineTo(-10,0);pointPath.arcTo(-10,0,20,20,180,180);QPainterPath inRing;inRing.addEllipse(-5,-5,10,10);painter.save();//计算并选择绘图对象坐标painter.rotate(-120);//设置画刷painter.setBrush(QColor(255,0,0,200));//绘制路径painter.drawPath(pointPath.subtracted(inRing));painter.restore();
}

这里指针加了一点点透明度,看上去有点点红黑的感觉,效果图如下所示:

在这里插入图片描述
六、最后总结
①这里只是绘制了一个静态表盘,如果要让指针动起来,修改指针的旋转角度即可。如果要有动画过度效果,那就得加定时器,定时调用绘制代码,让指针一点点的旋转过去,这里没有实现这个功能。
②上面描述的是绘制的整个过程,源码中,设置开始角度、结束角度、颜色,渐变颜色等一系列参数设置函数,可以根据自身需要设置不同的值,实现不同的效果。

七、代码获取
从Git下载,地址为:https://github.com/youyicc/Dashboard1.git

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/20268.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【车牌识别】模板匹配新能源、轿车、货车车牌识别【含GUI Matlab源码 2169期】

⛄一、模板匹配车牌识别简介 1 系统整体设计 车牌识别系统包括4个步骤:车牌定位 (包括识别图像中的车牌位置并将其分割) 、图像处理、字符分割与字符识别, 如图1所示。车牌定位的主要功能是从图像中可能包含车牌的候选区域中定位车牌区域;图像处理的功能是强化车牌关键特征;字…

做毕业设计,前端部分你需要掌握的6个核心技能

其实前端新手如果想要自己实现一套毕业设计项目并非简单的事,因为之前很多人一直还停留在知识点的阶段,而且管理系统和C端网站都需要开发,但现在需要点连成线了。所以在启动项目开发之前呢,针对前端部分,我列举一些非常必要的前端核心技能,希望你已掌握。 《Vue + Sprin…

【中创】ChatGPT技术被滥用,安全治理亟需政府、企业共同努力!

眼见为实&#xff1f;耳听为真&#xff1f;当心AI诈骗&#xff01; 只需要提供一张带脸的照片&#xff0c;就可以置换成明星&#xff0c;拟真度非常高&#xff0c;毫无违和感&#xff0c;一个软件就能直接将杨颖整成迪丽热巴&#xff01; 只要迪丽热巴的泪痣和嘴&#xff1f;没…

不信谣、不传谣?ChatGPT 技术滥用,浙江首个虚假制作团伙被抓获

根据绍兴公安群蓝星官方公众号的消息&#xff0c;绍兴上虞区公安分局最近成功打击了一个使用 ChatGPT技术制作虚假视频并在网络上散播谣言的犯罪团伙&#xff0c;已逮捕了3名嫌疑人。这是浙江省首个虚假视频制作团伙案件。 6月2日&#xff0c;上虞警方在网络巡查中注意到一个名…

医院在线预约挂号系统开源

小程序部分 开源地址&#xff1a;https://github.com/moyuc1966/Registerhttps://github.com/moyuc1966/Register 整体功能有&#xff1a; 用户注册部分、就诊人部分、就诊人管理、对预约记录&#xff0c;缴费充值退款记录的管理 意见反馈、医院公告&#xff08;文章&#x…

ChatGPT常用的指令(十二)——AI辅助医生、厨师、机械师

系列文章目录 内容翻译自&#xff1a;https://github.com/f/awesome-chatgpt-prompts&#xff0c;并加入自己的实践内容 1、 ChatGPT常用的提示语&#xff08;prompts&#xff09;系列一 2、 ChatGPT常用的提示语&#xff08;prompts&#xff09;系列二 3、 ChatGPT常用的提示语…

AI与医学辅助诊断

人工智能一词越来越频繁的出现在日常生活中。一种事物的时髦&#xff0c;必然有其背后的原因。而对于这样一个大的话题&#xff0c;从整体上来叙述总显得有些不接地气。作为跟AI沾过一些边的博主将以自己接触的方面来发表一点看法。 首先介绍一下&#xff0c;博主在研究生期间从…

马斯克亲吻美女机器人,AI时代要来了吗?

马斯克亲了一个机器人&#xff01; 你印象中的机器人是长什么样的呢&#xff1f;钢铁骨骼&#xff0c;机械四肢&#xff1f;一拳下去梆梆硬&#xff0c;我们自己还反而痛得飞起的材质&#xff1f;运气好的话有些机器人长得跟人类一样有脑袋有四肢、有个人体的大概轮廓&#xf…

Chat GPT原理

ChatGPT一经发布就在科技圈火得不行&#xff0c;这两天也是被传得神乎其神&#xff0c;听说它写得了代码、改得了 Bug&#xff0c;小说、段子统统不再话下&#xff01;那他到底是怎么训练成现在这样的呢&#xff1f;本文介绍李宏毅老师的分析。 那么接下来我们就来介绍Chat GPT…

探索 Apple 公司股价数据-Python实现

探索 Apple 公司股价数据 环境和数据题目代码详解这个例子比较适合数据挖掘入门一段时间。都还是比较基础的一些函数的应用。 环境和数据 这里使用的是pycharm2020.1.1 x64的 一般都是用的是Python 3.7.3 一些包就自己看着下 处理的数据 -appl_1980_2014.csv,如下图 题目 …

ChatGPT老板的核能公司要上市了,估值61亿

尚恩 发自 凹非寺量子位 | 公众号 QbitAI OpenAI CEO的核能公司&#xff0c;宣布上市&#xff01; Sam Altman旗下的核裂变初创公司Oklo Inc.已官宣&#xff0c;与空壳公司AltC Acquisition Corp.达成最终业务合并协议。 合并交易预计将于今年底或2024年初完成&#xff0c;合并…

【历史上的今天】2 月 24 日:乔布斯出生;苹果推出 Thunderbolt 接口;WhatsApp 创始人诞生

整理 | 王启隆 透过「历史上的今天」&#xff0c;从过去看未来&#xff0c;从现在亦可以改变未来。 今天是 2022 年 2 月 24 日&#xff0c;在 2010 年的今天&#xff0c;苹果公司宣布 iTunes 上面的音乐曲目下载量超过了 100 亿首&#xff0c;创下一大辉煌纪录&#xff1b;苹…

[苹果解密]创新是伟大公司诞生的源泉--Apple再度成为美国最大上市公司

近日不论美股还是A股&#xff0c;都是跌落的入水声一片&#xff0c;夹杂着小民的眼泪声和割肉声。但其中也发现了一个令人激动的消息&#xff1a;苹果已经成为美国最大上市公司&#xff01;大概在去年&#xff0c;苹果就已经是美股IT业最大市值的上市公司了&#xff0c;而今天&…

分析师意外下调评级为中性,苹果财报能否改变科技股走向?

新年的投资热情为苹果市值短暂达到3万亿美元铺平了道路&#xff0c;这是有史以来第一家跨过这一门槛的美国公司。尽管许多华尔街分析师和投资者对苹果的评级为看涨&#xff0c;但目前Seeking Alpha的量化评级给苹果的评级为中性(HOLD)。 苹果将于1月27日公布2022财年第一季度财…

苹果收购公司,为什么总是低调而高效---转自百度新闻|DTCHAT

苹果真的太壕了。有多壕&#xff1f;在很多年里面&#xff0c;苹果是全球最值钱的公司。为什么那么值钱&#xff1f;主要是因为它一点也不缺钱。最能存钱截至2022年末&#xff0c;苹果手里的现金、现金等价物和有价证券总价值为1654.5亿美元。那些亏损的企业看到这里&#xff0…

基于WebGPU的AI原生3D引擎将会迎来新机遇!Orillusion在GOTC上做主题演讲

全球开源技术峰会&#xff08;Global Open-source Technology Conference&#xff09; GOTC 2023 由开放原子开源基金会、 Linux 基金会亚太区、上海浦东软件园和开源中国联合发起&#xff0c; 于 5 月 27 日至 28 日在上海顺利举行。 GOTC是面向全球开发者的一场盛大开源技术…

就ChatGPT最近这情况......大家还是多一手准备吧

大家期待的经济繁荣&#xff0c;没有来。 往年的金三银四&#xff0c;跳槽涨薪&#xff0c;也没有来。 最近硅谷的大公司裁员了17万&#xff0c;三个月的裁员数&#xff0c;超过了去年一整年的。 中国估计也没好太多&#xff0c;只不过很多公司没有爆出来而已&#xff0c;大家都…

由浅入深之字符串的算法题(vs: chatGPT做算法)

背景 俗话说&#xff0c;温故而知新。chatGPT效果太惊艳了&#xff01;简直就是碾压的效果。但是还要有希望&#xff0c;先拾取&#xff0c;再创新。先了解&#xff0c;再超越吧。 ps: 再刷最后一遍算法题思路。顺便基于chatGPT3.5感受一下大模型的魔力。 字符串基础 C/C每个字…

Postman的使用:测试Excel文件导入导出

1.导入的测试方法 选择form-data,key值填写方法对应的参数&#xff0c;选择File&#xff0c;Value处上传文件即可。 2. 导出的测试方法 在导出文件的时候&#xff0c;响应结果是乱码&#xff0c;然后在测试的时候选择下载&#xff0c;下载完成的Excel文件不是乱码

postman 导出导入文件excel 请求方式设置

导出&#xff1a; 正常发送请求&#xff1a; 发送请求设置&#xff1a; 导入&#xff1a; post请求&#xff0c;接口参数 RequestParam("file") MultipartFile file