若该文为原创文章,未经允许不得转载
原博主博客地址:https://blog.csdn.net/qq21497936
原博主博客导航:https://blog.csdn.net/qq21497936/article/details/102478062
本文章博客地址:http://blog.csdn.net/qq21497936/article/details/77881844
各位读者,知识无穷而人力有穷,要么改需求,要么找专业人士,要么自己研究
红胖子(红模仿)的博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)持续更新中…(点击传送门)
Qt开发专栏:三方库开发技术(点击传送门)
《Qt开发笔记之Qwt开发笔记(一):Qwt介绍、编译与Demo》
《Qt开发笔记之Qwt开发笔记(二):Qwt仪表盘的基本使用》
背景
目前正在做云桌面,前面使用了QCursorPlot实现了二维图表,使用了QPropertyAnimation实现了按钮的抖动,现在需要一个动态显示空间的圆形效果图,如下图:
用100张图刷也可以,不过太原始了,所以研究研究Qwt,想使用Qwt仪表盘来实现。
前后关联
上一篇《Qt之Qwt初探(一)》我们介绍了扫盲了Qwt的官网图片示例的效果和代码提供示例的效果截图,
《Qt之Qwt初探(一)》: http://blog.csdn.net/qq21497936/article/details/77852657
本篇qwtDemo将实现下图的效果:
qwtDemo下载地址:http://download.csdn.net/download/qq21497936/9968406
本人对于qwt仪表盘的理解
Qwt的仪表盘分为三个部分,可分为“容器”,“表盘”,“指针”(名字是本人随便指定的,是否有专业的名次,请留言指正,谢谢!!!)。
1.“容器”部分QwtDial
仪表盘所在的dialog,有了dialog才能在dialog上面设置背景,需要仪表盘的时候需要先new一个QwtDial对象,起的作用与容器类似,本次继承了QwtDial在其构造函数中,new了仪表盘表盘部分,new了指针部分,分别做好初始化后,设置到容器上,类似于给“容器”托管了,设置的关键如下图:
…… //设置仪表盘背景到“容器”上 setScaleDraw(_pScaleDraw); …… //设置仪表盘指针到“容器”上 setNeedle( needle ); ……
2.仪表盘的表盘部分
表盘部分都是QwtAbstractScaleDraw的子类,具体读者可以自行查阅qwt的帮助文件。
_pScaleDraw=newQwtRoundScaleDraw(); //刻度线和标值之间的距离,默认为4pixels //_pScaleDraw->setSpacing(16); //是否显示将所有刻度连接起来的中心圆 _pScaleDraw->enableComponent(QwtAbstractScaleDraw::Backbone,true); //画线的宽度 // _pScaleDraw->setPenWidth(15); //修改颜色 QPalettepale=palette(); //中间的背景 // pale.setColor(QPalette::Foreground,Qt::red); //画线的颜色 pale.setColor(QPalette::Text,Qt::black); setPalette(pale); //是否显示刻度线,下面可以不设置刻度线了 _pScaleDraw->enableComponent(QwtAbstractScaleDraw::Ticks,false); //是否显示仪表盘刻度线周围的显示值 _pScaleDraw->enableComponent(QwtAbstractScaleDraw::Labels,false); //非主刻度线非中间刻度其他小刻度沿指针方向的长度,默认显示刻度线 _pScaleDraw->setTickLength(QwtScaleDiv::MinorTick,20); //主刻度线之间中间的刻度沿指针方向的长度,默认显示刻度线 _pScaleDraw->setTickLength(QwtScaleDiv::MediumTick,20); //主刻度线沿指针方向的长度,默认显示刻度线 _pScaleDraw->setTickLength(QwtScaleDiv::MajorTick,20); //设置仪表盘刻度层到主层上 setScaleDraw(_pScaleDraw); //???目前不太理解效果 setWrapping(false); //只读,如果只读则鼠标无法移动指针 setReadOnly(false); //起始角度,从中心右边横轴为0°,瞬时钟计算角度 setOrigin(270.0); // 角度范围,设置的其实角度为相对0°,相对于起始角度可活动多少度 // 设置范围0°,仍然有表盘,所以我们不显示 // 特别注意:我们使用动态控制表盘的刻度范围来实现空间的百分比效果,本Demo没有使用到指针 if(_radius<0.01) { _pScaleDraw->enableComponent(QwtAbstractScaleDraw::Backbone,false); }else { _pScaleDraw->enableComponent(QwtAbstractScaleDraw::Backbone,true); } setScaleArc(0.0,0.0);
3.仪表盘的指针部分
指针剪头分为多种,箭头类型的可实现一种颜色或者左右对阵与箭头中心显示两种颜色,实现的效果可参照Demo或者之前的该系列上一篇的博客,博客地址为:
http://blog.csdn.net/qq21497936/article/details/77852657
指针范例的代码如下图:
// QwtDialSimpleNeedle*needle=newQwtDialSimpleNeedle( // QwtDialSimpleNeedle::Arrow,true,Qt::red, // QColor(Qt::gray).light(130)); //设置仪表盘指针到容器上 // setNeedle(needle);
实现步骤
1. 初始化仪表盘
设置仪表盘的表盘,没有指针所以不设置(后面开发的过程中,发现qwt本身是无法实现我们要的效果,需要我们重新补充其他部分)。
下面是继承了QwtDial的类的构造函数中的初始化代码:
MSpacePanel::MSpacePanel(QWidget*parent): QwtDial(parent), _radius(0.0) { QPalettepa(palette()); pa.setColor(QPalette::Foreground,Qt::black); pa.setColor(QPalette::Text,Qt::black); pa.setColor(QPalette::Background,Qt::black); //显示百分比的lable _pLabel=newQLabel(this); _pLabel->setPalette(pa); _pLabel->show(); //显示百分比下面文字信息的lable _pLabel2=newQLabel(this); _pLabel2->setPalette(pa); _pLabel2->show(); _pScaleDraw=newQwtRoundScaleDraw(); //刻度线和标值之间的距离,默认为4pixels //_pScaleDraw->setSpacing(16); //是否显示将所有刻度连接起来的中心圆 _pScaleDraw->enableComponent(QwtAbstractScaleDraw::Backbone,true); //画线的宽度 // _pScaleDraw->setPenWidth(15); //修改颜色 QPalettepale=palette(); //中间的背景 // pale.setColor(QPalette::Foreground,Qt::red); //画线的颜色 pale.setColor(QPalette::Text,Qt::black); setPalette(pale); //是否显示刻度线,下面可以不设置刻度线了 _pScaleDraw->enableComponent(QwtAbstractScaleDraw::Ticks,false); //是否显示仪表盘刻度线周围的显示值 _pScaleDraw->enableComponent(QwtAbstractScaleDraw::Labels,false); //非主刻度线非中间刻度其他小刻度沿指针方向的长度,默认显示刻度线 _pScaleDraw->setTickLength(QwtScaleDiv::MinorTick,20); //主刻度线之间中间的刻度沿指针方向的长度,默认显示刻度线 _pScaleDraw->setTickLength(QwtScaleDiv::MediumTick,20); //主刻度线沿指针方向的长度,默认显示刻度线 _pScaleDraw->setTickLength(QwtScaleDiv::MajorTick,20); //设置仪表盘刻度层到主层上 setScaleDraw(_pScaleDraw); //???目前不太理解效果 setWrapping(false); //只读,如果只读则鼠标无法移动指针 setReadOnly(false); //起始角度,从中心右边横轴为0°,瞬时钟计算角度 setOrigin(270.0); //角度范围,设置的其实角度为相对0°,相对于起始角度可活动多少度 //设置范围0°,仍然有表盘,所以我们不显示 //特别注意:我们使用动态控制表盘的刻度范围来实现空间的百分比效果,本Demo没有使用到指针 if(_radius<0.01) { _pScaleDraw->enableComponent(QwtAbstractScaleDraw::Backbone,false); }else { _pScaleDraw->enableComponent(QwtAbstractScaleDraw::Backbone,true); } setScaleArc(0.0,0.0); //注释掉指针 // QwtDialSimpleNeedle*needle=newQwtDialSimpleNeedle( // QwtDialSimpleNeedle::Arrow,true,Qt::red, // QColor(Qt::gray).light(130)); //设置仪表盘指针到容器上 // setNeedle(needle); _propertyAnimation.setTargetObject(this); _propertyAnimation.setPropertyName("radius"); _propertyAnimation.setStartValue(0.0); _propertyAnimation.setEndValue(0.0); _propertyAnimation.setDuration(DURATION_MS); _propertyAnimation.setEasingCurve(QEasingCurve::OutQuad); _propertyAnimation.start(); }
上文中使用了动画的效果,主要目的是使指针变数缓冲,动画效果的类实例_propertyAnimation,其中值得注意的是属性setPropertyName()函数的参数radius,这个我们在类声明的时候是手动注册的属性,注册的方法有两个步骤,步骤如下:
第一步:添加成员变量,添加成员变量读/写函数,如下:
class MSpacePanel:public QwtDial { …… private: …… double getRadius()const; void setRadius(constdoubleradius); …… private: …… double _radius; …… }
第二步:注册为属性
class MSpacePanel:public QwtDial { Q_OBJECT //自定义属性 Q_PROPERTY(double radius READ getRadius WRITEsetRadius) …… }
2.resize窗口大小要做的事情
voidMSpacePanel::resizeEvent(QResizeEvent*event) { _w=geometry().width(); _h=geometry().height(); _pLabel->setStyleSheet(QString("font:%1px").arg((int)(_w/4))); _pLabel->setGeometry((_w-_w/2.5)/2-10,(_h-_h/3)/2,_w/2.5+20,_h/3); _pLabel->setAlignment(Qt::AlignHCenter); _pLabel2->setStyleSheet(QString("font:%1px").arg((int)(_w/8))); _pLabel2->setGeometry((_w-_w/2.5)/2-20,(_h-_h/3)/2+50,_w/2.5+50,_h/3); _pLabel2->setAlignment(Qt::AlignHCenter); _pLabel2->setText("空间使用率"); _pScaleDraw->setPenWidth(_w/15); _penWidth=_pScaleDraw->penWidth(); }
3.重画窗口需要设置值
主要是限制最大值最小值和动画效果,动画不能使用pause,否则会直接设置到值(接上次剩余的时间到endValue),应该是stop然后重新开始运行动画。
voidMSpacePanel::setValue(double value) { if(value>100.0) value=100.0; elseif(value<0.01) value=0; _propertyAnimation.stop(); _propertyAnimation.setDuration(DURATION_MS); _propertyAnimation.setStartValue(_propertyAnimation.currentValue().toDouble()); _propertyAnimation.setEndValue(value*3.6); _propertyAnimation.start(); }
4.实现我们的效果(还有空间未使用部分的灰色没有实现)
为了实现我们的效果,只能重载painter函数,使用QPainter补充画剩余的圆弧,代码如下:
voidMSpacePanel::paintEvent(QPaintEvent*event) { //调用基类,画基类 QwtDial::paintEvent(event); //在已有的图形上画 QPainter painter(this); painter.setPen(QPen(QColor(199,199,199),15)); double space=13.5f; // qDebug()<<__FILE__<<__LINE__<<_radius*16<<360*16<<_w<<_h; painter.drawArc(0+space,0+space, _w-space*2,_h-space*2,90*16,360*16-_radius*16); }
总结
本次项目中需要实现的效果使用qwt完成,在开发的过程中,对qwt进一步了解,我们可以发现,需要实现的效果其实直接使用QPainter画图完成更好,我们主要的目的是实现效果的同时熟悉qwt技术,本次需求该效果的项目中将不会使用qwt完成。
原博主博客地址:https://blog.csdn.net/qq21497936
原博主博客导航:https://blog.csdn.net/qq21497936/article/details/102478062
本文章博客地址:http://blog.csdn.net/qq21497936/article/details/77881844