• 2533阅读
  • 3回复

Qt编写数据可视化大屏界面电子看板11-自定义控件 [复制链接]

上一主题 下一主题
离线liudianwu
 

只看楼主 倒序阅读 楼主  发表于: 2019-05-21

一、前言
说到自定义控件,我是感觉特别熟悉的几个字,本人亲自原创的自定义控件超过110个,都是来自各个行业的具体应用真实需求,而不是凭空捏造的,当然有几个小控件也有点凑数的嫌疑,在编写整个数据可视化大屏界面电子看板系统中,也用到了四五个自定义的控件,比如那个环形百分比图,多态进度条,合格率仪表盘,速度仪表盘等,这些控件在现有的类中是没有的,需要用QPainter这个牛逼的工具来绘制,类似于神笔马良似的,给我一个画笔,可以画出任意你想要的图形,好比我常说的心中有坐标,万物皆painter。

自定义控件为了适应整体换肤,需要用Q_PROPERTY类指定,类似于元对象,用Q_PROPERTY指定的东西,可以直接样式表控制,比如GaugePercent{qproperty-baseColor:#FF0000;}就可以对所有的GaugePercent类进行颜色更换,而且是动态更换,用Q_PROPERTY指定的东西还可以直接出现在Qtcreator的右侧属性栏,直接修改属性即可,所见即所得,非常方便。

二、电子看板介绍
电子看板是目视化管理的一种表现形式,即对数据的状况一目了然地表现,主要是对于管理项目,它通过利用形象直观而又色彩适宜的各种视觉感知信息来组织现场生产活动,目视管理依据人类的生理特征,在生产现场充分利用信号灯、标识牌、符号颜色等方式来发出视觉信号,鲜明准确地刺激人的神经末梢,快速地传递信息,形象直观地将潜在的问题和浪费现象都显现出来。以便任何人都可以及时掌握管理现状和必要的情报,从而能够快速制定并实施应对措施。因此,管理看板是发现问题、解决问题的非常有效且直观的手段,是优秀的现场管理必不可少的工具之一。

三、功能特点
1. 整体总共分三级界面,一级界面是整体布局,二级界面是单个功能模块,三级界面是单个控件。
2. 子控件包括饼图+圆环图+曲线图+柱状图+柱状分组图+横向柱状图+横向柱状分组图+合格率控件+百分比控件+进度控件+设备状态面板+表格数据+地图控件(包括动态闪烁点+迁徙图等)+视频控件+其他控件等。
3. 二级界面可以自由拖动悬浮,支持最小化最大化关闭,响应双击自定义标题栏。
4. 数据源支持数据库采集(默认)、网络通信、网络请求等,可自由设定每个子界面的采集间隔即数据刷新频率。
5. 采用纯QWidget编写,支持Qt4.6到Qt5.12.3任何版本,支持嵌入式linux比如树莓派、香橙派、全志、imx6等。
6. 提供三个内核版本,自定义控件版本+qchart版本+echart版本。
7. 内置多套配色风格样式,默认紫色,支持任何分辨率。
8. 可设置标题+目标分辨率+布局方案,启动立即应用。
9. 可设置主背景颜色+面板颜色+十字线游标颜色。
10. 可设置多条曲线颜色,没有设置颜色的情况下内置15套精美颜色随机应用。
11. 可设置标题栏背景颜色+文字颜色。
12. 可设置曲线图表背景颜色+文字颜色+网格颜色。
13. 可设置正常颜色+警戒颜色+报警颜色+禁用颜色+百分比进度颜色。
14. 可分别设置各种字体大小,比如全局+软件名称+标题栏+子标题栏+加粗标签等。
15. 可设置标题栏高度+表头高度+行高度。
16. 曲线支持游标+悬停高亮数据点和显示值,柱状图支持顶部(可设置顶端+上部+中间+底部)显示数据,全部自适应计算位置。
17. 主界面直接鼠标右键切换布局+配色方案+关闭开启某个二级窗体。
18. 自动记忆所有子窗口的大小和位置,下次启动立即应用。
19. 动态加载布局方案菜单,可以动态新建布局、恢复布局、保存布局、另存布局等,用户可以制造任意布局。
20. 二级窗体,双击从主窗体分离出来浮动,可以自由调整大小。再次双击标题栏最大化,再次双击还原。
21. 每个模块都可以自定义采集速度,如果是数据库采集会自动排队处理。


五、特别说明
1. 可执行文件同级文件夹有layout+layout_1440+layout_1920,程序默认自动识别分辨率并加载对应的布局文件夹,比如1920分辨率则从layout_1920文件夹加载布局,并作为整体布局文件夹。
2. 程序默认是模拟数据,如果需要从数据库采集则修改配置文件WorkMode=db即可。
3. 如果发现布局拖动乱了,可以直接鼠标右键选择恢复布局即可,在保存布局以前。
4. 在中间地图模块鼠标右键可以弹出菜单,切换布局和配色方案等。
5. 在模块的标题栏上右键可以弹出默认的dock菜单,用来显示和隐藏各模块。
6. 软件关闭过程中会自动保存布局,下次启动以后自动应用。
7. 如果使用的默认的默认的配色方案比如紫色风格,则配置文件中的颜色全部无效,会自动应用代码中的颜色,如果需要启用自定义的颜色,则将配置文件的 Theme=\x81ea\x5b9a\x4e49\x98ce\x683c 即可。此时打开软件会应用配置文件中的颜色。
8. 右键菜单可以截图保存,默认命名为 配色方案名称_布局方案名称.png 保存在snap目录下。
9. 如果是XP系统请先执行fixff.cmd,用来修复ffmpeg在XP上不可用的BUG。
10. 在二级窗体的标题栏上右键弹出模块菜单,可以对单个模块打开关闭,其他地方右键全局菜单。
11. 可执行文件下载地址:https://pan.baidu.com/s/1o97IGvZgTgDhlkuXQa4B0w 提取码:r2bv。
12. 会不定期更新程序,欢迎各位提出批评和建议。

六、效果图


七、核心代码
  1. void ProgressRing::paintEvent(QPaintEvent *)
  2. {
  3.     int width = this->width();
  4.     int height = this->height();
  5.     int side = qMin(width, height);
  6.     //绘制准备工作,启用反锯齿,平移坐标轴中心,等比例缩放
  7.     QPainter painter(this);
  8.     painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
  9.     painter.translate(width / 2, height / 2);
  10.     painter.scale(side / 200.0, side / 200.0);
  11.     //绘制背景
  12.     drawBg(&painter);
  13.     //绘制进度
  14.     drawRing(&painter);
  15.     //绘制间隔,重新绘制一个圆遮住,产生间距效果
  16.     if (ringPadding > 0) {
  17.         drawPadding(&painter);
  18.     }
  19.     //绘制中间圆
  20.     drawCircle(&painter);
  21.     //绘制当前值
  22.     drawValue(&painter);
  23. }
  24. void ProgressRing::drawBg(QPainter *painter)
  25. {
  26.     int radius = 99;
  27.     painter->save();
  28.     painter->setPen(Qt::NoPen);
  29.     //这里有个技巧,如果没有间距则设置成圆环的背景色
  30.     painter->setBrush(ringPadding == 0 ? ringBgColor : bgColor);
  31.     painter->drawEllipse(-radius, -radius, radius * 2, radius * 2);
  32.     painter->restore();
  33. }
  34. void ProgressRing::drawRing(QPainter *painter)
  35. {
  36.     int radius = 99 - ringPadding;
  37.     painter->save();
  38.     painter->setPen(Qt::NoPen);
  39.     painter->setBrush(ringColor);
  40.     QRectF rect(-radius, -radius, radius * 2, radius * 2);
  41.     //计算总范围角度,当前值范围角度,剩余值范围角度
  42.     double angleAll = 360.0;
  43.     double angleCurrent = angleAll * ((currentValue - minValue) / (maxValue - minValue));
  44.     double angleOther = angleAll - angleCurrent;
  45.     //如果逆时针
  46.     if (!clockWise) {
  47.         angleCurrent = -angleCurrent;
  48.         angleOther = -angleOther;
  49.     }
  50.     //动态设置当前进度颜色
  51.     QColor color = ringColor;
  52.     if (alarmMode == 1) {
  53.         if (currentValue >= ringValue3) {
  54.             color = ringColor3;
  55.         } else if (currentValue >= ringValue2) {
  56.             color = ringColor2;
  57.         } else {
  58.             color = ringColor1;
  59.         }
  60.     } else if (alarmMode == 2) {
  61.         if (currentValue <= ringValue1) {
  62.             color = ringColor1;
  63.         } else if (currentValue <= ringValue2) {
  64.             color = ringColor2;
  65.         } else {
  66.             color = ringColor3;
  67.         }
  68.     }
  69.     //绘制当前值饼圆
  70.     painter->setBrush(color);
  71.     painter->drawPie(rect, (startAngle - angleCurrent) * 16, angleCurrent * 16);
  72.     //绘制剩余值饼圆
  73.     painter->setBrush(ringBgColor);
  74.     painter->drawPie(rect, (startAngle - angleCurrent - angleOther) * 16, angleOther * 16);
  75.     painter->restore();
  76. }
  77. void ProgressRing::drawPadding(QPainter *painter)
  78. {
  79.     int radius = 99 - ringWidth - ringPadding;
  80.     painter->save();
  81.     painter->setPen(Qt::NoPen);
  82.     painter->setBrush(bgColor);
  83.     painter->drawEllipse(-radius, -radius, radius * 2, radius * 2);
  84.     painter->restore();
  85. }
  86. void ProgressRing::drawCircle(QPainter *painter)
  87. {
  88.     //文字的区域要减去进度的宽度及间距
  89.     int radius = 99 - ringWidth - (ringPadding * 2);
  90.     painter->save();
  91.     painter->setPen(Qt::NoPen);
  92.     painter->setBrush(circleColor);
  93.     painter->drawEllipse(-radius, -radius, radius * 2, radius * 2);
  94.     painter->restore();
  95. }
  96. void ProgressRing::drawValue(QPainter *painter)
  97. {
  98.     //文字的区域要减去进度的宽度及间距
  99.     int radius = 99 - ringWidth - (ringPadding * 2);
  100.     painter->save();
  101.     painter->setPen(textColor);
  102.     QFont font;
  103.     int fontSize = radius - (showPercent ? 20 : 6);
  104.     font.setPixelSize(fontSize);
  105.     painter->setFont(font);
  106.     QRectF textRect(-radius, -radius, radius * 2, radius * 2);
  107.     QString strValue;
  108.     if (showPercent) {
  109.         double percent = (currentValue * 100) / (maxValue - minValue);
  110.         strValue = QString("%1%").arg(percent, 0, 'f', precision);
  111.     } else {
  112.         strValue = QString("%1").arg(currentValue, 0, 'f', precision);
  113.     }
  114.     //如果定义了显示的文字则优先显示
  115.     strValue = text.isEmpty() ? strValue : text;
  116.     painter->drawText(textRect, Qt::AlignCenter, strValue);
  117.     painter->restore();
  118. }


欢迎关注微信公众号:Qt实战 (各种开源作品、经验整理、项目实战技巧,专注Qt/C++软件开发,视频监控、物联网、工业控制、嵌入式软件、国产化系统应用软件开发)QQ:517216493  WX:feiyangqingyun  QQ群:751439350

只看该作者 1楼 发表于: 2019-05-22
代码之前分享过了重复了
离线305750665

只看该作者 2楼 发表于: 2019-05-22
刘总又多了一个外号了。刘马良大佬,你好!
雨田哥: 群号:853086607
QQ: 3246214072

刘典武-feiyangqingyun:专业各种自定义控件编写+UI定制+输入法定制+视频监控+工业控制+仪器仪表+嵌入式linux+各种串口网络通信,童叟无欺,量大从优,欢迎咨询购买定制!QQ:517216493
离线fight傲

只看该作者 3楼 发表于: 2019-06-03
为啥分享的资源都删了呀
快速回复
限100 字节
 
上一个 下一个