Qt编写物联网管理平台34-地图按钮
一、前言
地图按钮很常见,这也是用户给钱就干的一个模块。设备现场提供了对应的地图文件,其实就是图片文件,做的简单点就是直接CAD图纸转成jpg,做的精致点就是搞了3D风格的立体样式图片,其实还是图片,并不是真正的3D,看起来像是3D的感觉。很多人看到效果图都来问这个3D怎么实现的,真正的3D实现都非常复杂,需要懂opengl,网页上用的是webgl,当然也有不少的轮子可以直接使用。
地图按钮就是一个终端传感器作为一个按钮点,分布在对应的图片文件上,其实就是父类设置为label,label显示对应的图片。图片大小的算法,目前采用的当前分辨率计算,当前分辨率减去上下左右的尺寸就是图片应该的尺寸,拉伸填充显示,所以要求用户提供的图片最好按照现场电脑的分辨率比例来设置,这样不会显得拉伸变形,后期这一块需要改进算法,难点就是按钮在设置界面的相对位置不好计算,除非是绘制上去的。
地图按钮几个特色功能:
- 从内存中而不是文件取图片显示,响应速度微秒级别。
- 报警自动切换到对应的地图。
- 不同状态不同颜色显示,报警红色或者黄色闪烁。
- 按钮位置在编辑状态下,任意拖动,自动保存。
- 提供缩略图导航,可手动切换。
- 在线状态显示对应的值和单位符号,离线状态显示位置编号。
二、功能特点
2.1 软件模块
- 设备监控模块,包括数据监控(表格形式展示)、设备面板(面板形式展示)、地图监控(地图形式展示)、曲线监控(曲线形式展示)。
- 数据查询模块,包括报警记录、运行记录、操作记录。
- 系统设置模块,包括基本设置、端口管理、控制器管理、探测器管理、报警联动、类型设置等。
- 其他设置模块,包括用户管理、地图管理、位置调整、组态设计、设备调试等。
2.2 基础功能
- 设备数据采集,支持串口、网络,串口可设置串口号、波特率,网络可设置IP地址、通讯端口。
- 每个端口支持采集周期时间,默认1秒钟一个设备。
- 支持设置通讯超时次数,默认3次。
- 支持最大重连时间,用于重新读取离线的设备。
- 控制器信息,能够添加控制器名称,选择控制器地址、控制器型号,设置该控制器下面的探测器数量。
- 探测器信息,能够添加位号、探测器型号、气体种类、气体符号、高报值、低报值、缓冲值、清零值、是否启用、报警声音、背景地图、存储周期、数值换算小数点位数、报警延时时间、报警的类型(HH,LL,HL)等。
- 类型管理可配置控制器型号、探测器型号、气体种类、气体符号等。
- 地图支持导入和删除,所有的探测器在地图上的位置可自由拖动保存。
- 端口信息、控制器信息、探测器信息、类型信息、用户信息等,都支持导入、导出、导出到excel、打印。
- 运行记录、报警记录、操作记录,都支持多条件组合查询,比如时间段、控制器、探测器等,所有记录支持导出到excel/pdf和打印。
- 运行记录、报警记录、操作记录都可删除指定时间范围内的数据。
- 系统设置可选择对应表最大保存记录数,自动清理早期数据,留出足够的空间存储重要的数据。
- 报警短信转发,支持多个接收手机号码,可设定发送间隔,比如即时发送或者6个小时发送一次所有的报警信息,短信内容过长,自动拆分多条短信。
- 报警邮件转发,支持多个接收邮箱,可设定发送间隔,比如即时发送或者6个小时发送一次所有的报警信息,支持附件发送。
- 设置软件的中文标题、英文标题、logo路径、版权所有等。
- 开关设置开机运行、报警声音、自动登录、记住密码等。
- 报警声音可设置播放次数,界面风格样式提供18套皮肤文件选择。
- 用户管理,包括用户权限配置,不同用户可以有不同模块的权限。
- 用户登录和用户退出,可以记住密码和自动登录,超过三次报错提示并关闭程序。
- 四种监控模式,设备面板监控、地图监控、表格数据监控、曲线数据监控,可自由切换,四种模式下都实时展示采集到的数据,报警闪烁等。
- 报警继电器联动,一个位号可以跨串口联动多个模块和继电器号,支持多对多。
2.3 特色功能
- 通信协议支持modbus_com、modbus_tcp_rtu,后期拓展mqtt等协议。
- 数据源除了真实的硬件设备采集,还可选数据库采集,这样用户可以安排其他程序员比如java程序员将前端采集好的数据放到数据库,本系统直接从数据库采集即可。数据库采集模式可以作为通用的系统使用,更适合多人多系统协作。
- 智能跳过超时的设备,加快对在线设备的采集速度,当设备数量很多的时候尤其有用。
- 对智能跳过的超时的设备,在设定的重连时间自动采集一次,以便探测设备是否又重新上线。
- 每个探测器可控是否启用,不启用则不会采集,也不会在界面显示,相当于运行阶段临时关闭。
- 探测器可设置缓冲值和报警延时时间,在该值附近波动产生的报警,不计入报警,只有持续处于报警值且超过报警延时时间才算真正报警,这样可以规避很多波动导致的误报。
- 探测器可设置存储周期,按照设定的时间来存储一条运行记录,可以按照重要程度对重要性高的设定存储周期短一些,不重要的设定大一些,这样可以节省不少的存储空间,也保证了重要的数据及时存储。
- 探测器可设置清零值,在一些高精度高灵敏的设备可能出厂的时候默认值未必是0,需要设定清零值来表示初始值。
- 探测器可设置小数点,用于计算后的真实数据控制小数点点位显示,相当于除以10、除以100、除以1000,这样大部分的探测器数据直接通过小数点位设置控制真实换算后的值,极个别的需要特殊转换的可以在通信协议中约定。
- 探测器报警的类型支持多种,有些设备是高于某个值高报,低于某个值低报,而有些设备是在最小值最大值范围内是高报,低于最小值低报,高于最大值正常。这样可以分情况处理,涵盖各种报警类型。
- 原创数据导入、导出、打印机制,跨平台不依赖任何组件,瞬间导出数据。
- 导出到excel的记录支持所有excel、wps等表格文件版本,不依赖excel等软件。
- 高报颜色、低报颜色、正常颜色、默认值颜色等,都可以自由设置。
- 支持云端数据同步,将本地采集到的数据实时同步到云端。
- 支持网络转发和网络接收,网络接收开启后,软件从udp接收数据进行解析。网络转发支持多个目标IP,这样就实现了本地采集的软件,自由将数据转到客户端,随时查看采集到的数据。
- 自动记住用户最后停留的界面以及其他配置信息,重启后自动应用。
- 报警自动切换到对应的地图,探测器按钮闪烁,表格数据对应颜色显示。
- 双击探测器图标,弹出对应探测器详细信息,可以根据需要定制回控操作。
- 数据库支持多种,包括sqlite、mysql、sqlserver、postgresql、oracle、人大金仓等。
- 本地设备采集到的数据实时上传到云端,以便手机APP或者web等其他方式提取。
- 自带设备模拟工具,支持不同型号的多个设备数据模拟,同时还带数据库数据模拟,以便在没有设备的时候测试数据。
- 标准modbus协议,各种控制器类型、探测器类型、种类、符号等全部自定义,非常灵活和强大,通信协议示例数据非常完整,通用各种modbus协议系统,适用于各种应用场景接入。
- 同时集成了串口通信、网络通信、数据库通信、数据导入导出打印、通信协议解析、界面UI、全局换肤等众多组件和知识点,非常适合新手入门和进阶。
- 支持xp、win7、win10、、win11、linux、mac、各种国产系统(UOS、中标麒麟、银河麒麟等)、嵌入式linux等系统。
- 注释完整,项目结构清晰,超级详细完整的使用开发手册,精确到每个代码文件的功能说明,不断持续迭代版本。
三、体验地址
- 国内站点:https://gitee.com/feiyangqingyun
- 国际站点:https://github.com/feiyangqingyun
- 个人主页:https://blog.csdn.net/feiyangqingyun
- 知乎主页:https://www.zhihu.com/people/feiyangqingyun
- 产品主页:https://blog.csdn.net/feiyangqingyun/article/details/97565652
- 在线文档:https://feiyangqingyun.gitee.io/qwidgetdemo/iotsystem/
- 体验地址:https://pan.baidu.com/s/1ZxG-oyUKe286LPMPxOrO2A 提取码:o05q 文件名:bin_iotsystem.zip。
- 文章导航:https://qtchina.blog.csdn.net/article/details/121330922
四、效果图

五、相关代码
void DeviceHelper::initDeviceButton(QLabel *label)
{
if (labMap == NULL) {
return;
}
//先清空原来的
bool isMain = (labMap == label);
if (isMain) {
qDeleteAll(btns);
btns.clear();
} else {
qDeleteAll(btns2);
btns2.clear();
}
for (int i = 0; i < DbData::NodeInfo_Count; ++i) {
//地图为空的不需要
if (DbData::NodeInfo_NodeImage.at(i).contains("无")) {
continue;
}
DeviceButton *btn = new DeviceButton(label);
btn->setButtonStyle(DeviceButton::ButtonStyle_Msg2);
btn->resize(AppData::DeviceWidth, AppData::DeviceHeight);
btn->setText(QString("%1").arg(DbData::NodeInfo_PositionID.at(i)));
btn->setButtonColor(isMain ? DeviceButton::ButtonColor_Black : DeviceButton::ButtonColor_Green);
btn->setCanMove(!isMain);
//设置弱属性
btn->setProperty("nodeID", DbData::NodeInfo_NodeID.at(i));
btn->setProperty("positionID", DbData::NodeInfo_PositionID.at(i));
btn->setProperty("deviceName", DbData::NodeInfo_DeviceName.at(i));
btn->setProperty("nodeName", DbData::NodeInfo_NodeName.at(i));
btn->setProperty("nodeAddr", DbData::NodeInfo_NodeAddr.at(i));
btn->setProperty("nodeType", DbData::NodeInfo_NodeType.at(i));
btn->setProperty("nodeSign", DbData::NodeInfo_NodeSign.at(i));
btn->setProperty("nodeImage", DbData::NodeInfo_NodeImage.at(i));
//设置位置
int x = DbData::NodeInfo_NodeX.at(i);
int y = DbData::NodeInfo_NodeY.at(i);
btn->move(x, y);
if (isMain) {
btns << btn;
QObject::connect(btn, SIGNAL(doubleClicked()), AppEvent::Instance(), SLOT(slot_doubleClicked()));
} else {
btns2 << btn;
}
}
}
void DeviceButton::paintEvent(QPaintEvent *)
{
double width = this->width();
double height = this->height();
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
//绘制背景图
QImage img(imgName);
if (!img.isNull()) {
img = img.scaled(width, height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
painter.drawImage(0, 0, img);
}
//计算字体
QFont font;
font.setPixelSize(height * 0.37);
font.setBold(true);
//自动计算文字绘制区域,绘制防区号
QRectF rect = this->rect();
if (buttonStyle == ButtonStyle_Police) {
double y = (30 * height / 60);
rect = QRectF(0, y, width, height - y);
} else if (buttonStyle == ButtonStyle_Bubble) {
double y = (8 * height / 60);
rect = QRectF(0, 0, width, height - y);
} else if (buttonStyle == ButtonStyle_Bubble2) {
double y = (13 * height / 60);
rect = QRectF(0, 0, width, height - y);
font.setPixelSize(width * 0.33);
} else if (buttonStyle == ButtonStyle_Msg) {
double y = (17 * height / 60);
rect = QRectF(0, 0, width, height - y);
} else if (buttonStyle == ButtonStyle_Msg2) {
double y = (17 * height / 60);
rect = QRectF(0, 0, width, height - y);
}
//绘制文字标识
painter.setFont(font);
painter.setPen(Qt::white);
painter.drawText(rect, Qt::AlignCenter, text);
}
bool DeviceButton::eventFilter(QObject *watched, QEvent *event)
{
//识别鼠标 按下+移动+松开+双击 等事件
QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
if (event->type() == QEvent::MouseButtonPress) {
//限定鼠标左键
if (mouseEvent->button() == Qt::LeftButton) {
lastPoint = mouseEvent->pos();
isPressed = true;
emit clicked();
return true;
}
} else if (event->type() == QEvent::MouseMove) {
//允许拖动并且鼠标按下准备拖动
if (canMove && isPressed) {
int dx = mouseEvent->pos().x() - lastPoint.x();
int dy = mouseEvent->pos().y() - lastPoint.y();
this->move(this->x() + dx, this->y() + dy);
return true;
}
} else if (event->type() == QEvent::MouseButtonRelease) {
isPressed = false;
} else if (event->type() == QEvent::MouseButtonDblClick) {
emit doubleClicked();
}
return QWidget::eventFilter(watched, event);
}
Qt编写物联网管理平台34-地图按钮的更多相关文章
- 年底奉献-QT编写视频监管平台(开源)
忙忙碌碌又是一年,算算自己毕业四年半,一直在现在这家公司做研发外加总经理助理,研发起初用的VB.NET,而后全面转为C#,最后又全面转为QT,都是由于项目需要,算下来自己搞QT编程也已经四年了,201 ...
- Qt编写可拖动对象+背景地图+多种样式+多种状态(开源)
在很多项目应用中,需要根据数据动态生成对象显示在地图上,比如地图标注,同时还需要可拖动对象到指定位置显示,能有多种状态指示,为此特意编写本控件,全部开源出来,欢迎大家提建议.同时多多支持整套自定义控件 ...
- Qt编写的开源帖子集合(懒人专用)
回顾自己学习Qt以来九年了,在这九年多时间里面,从本论坛学习不到不少的东西,今天特意整了一下自己开源过的资源的帖子,整理一起方便大家直接跳转下载,不统计不知道,一统计吓一跳,不知不觉开源了这么多代码, ...
- EASYUI+MVC4通用权限管理平台
通用权限案例平台在经过几年的实际项目使用,并取得了不错的用户好评.在平台开发完成后,特抽空总结一下平台知识,请各位在以后的时间里,关注博客的更新. 1.EASYUI+MVC4通用权限管理平台--前言 ...
- (转)EASYUI+MVC4通用权限管理平台
原文地址:http://www.cnblogs.com/hn731/archive/2013/07/15/3190947.html 通用权限案例平台在经过几年的实际项目使用,并取得了不错的用户好评.在 ...
- 自学华为IoT物联网_10 IoT联接管理平台配置及开发实验1
点击返回自学华为IoT物流网 自学华为IoT物联网_10 IoT联接管理平台配置及开发实验1 实验1:OceanConnect平台实验 通过基本的编程操作与配置,帮助读者熟悉O ...
- Qt编写自定义控件二动画按钮
现在的web发展越来越快,很多流行的布局样式,都是从web开始的,写惯了Qt widgets 项目,很多时候想改进一下现有的人机交互,尤其是在现有的按钮上加一些动画的效果,例如鼠标移上去变大,移开还原 ...
- Qt编写自定义控件11-设备防区按钮控件
前言 在很多项目应用中,需要根据数据动态生成对象显示在地图上,比如地图标注,同时还需要可拖动对象到指定位置显示,能有多种状态指示,安防领域一般用来表示防区或者设备,可以直接显示防区号,有多种状态颜色指 ...
- Qt编写自定义控件38-高亮按钮
一.前言 高亮按钮控件,既可以作为类似于交通指示灯使用,也可以作为设备状态指示灯使用,控件内置多套颜色风格,还可以自己设置颜色风格,按钮可以增加文字显示,非常适合需要在状态设备上显示小量的文字展示,按 ...
- 自学华为IoT物联网_08 IoT连接管理平台介绍
点击返回自学华为IoT物流网 自学华为IoT物联网_08 IoT连接管理平台介绍 一.IoT连接管理平台的由来 1.1 物联网产业发展面临的挑战 新业务上线周期长,应用碎片化,开发周期长,场频上市慢 ...
随机推荐
- 06 - react的类组件中的状态state render函数 this指向问题 事件绑定
// 注册事件 import ReactDom from "react-dom" import { Component } from "react" // 类组 ...
- C#查漏补缺----Exception处理实现,无脑抛异常不可取
前言 环境:.NET 8.0 系统:Windows11 参考资料:CLR via C#, .Net Core底层入门 https://andreabergia.com/blog/2023/05/err ...
- kotlin协程——>异步流
异步流 挂起函数可以异步的返回单个值,但是该如何异步返回多个计算好的值呢?这正是 Kotlin 流(Flow)的 ⽤武之地. 表示多个值 在 Kotlin 中可以使⽤集合来表⽰多个值.⽐如说,我们可以 ...
- Kafka原理剖析之「Purgatory(炼狱 | 时间轮)」
一.前言 本文介绍一下Kafka赫赫有名的组件Purgatory,相信做Kafka的朋友或多或少都对其有一定的了解,至少是听过它的名字.那它的作用是什么呢,用来解决什么问题呢?官网confluent早 ...
- KubeSphere 社区双周报 | KubeSphere 多项更新 | 2023.06.23-07.06
KubeSphere 社区双周报主要整理展示新增的贡献者名单和证书.新增的讲师证书以及两周内提交过 commit 的贡献者,并对近期重要的 PR 进行解析,同时还包含了线上/线下活动和布道推广等一系列 ...
- ES6语法特性
ES6语法特性 简介 ECMAScript 6.0(以下简称 ES6)是 JavaScript 语言的下一代标准,已经在 2015 年 6 月正式发布了. 它的目标,是使得 JavaScript 语言 ...
- Mac安装Docker
一.下载 从官网下载速度太慢,推荐在阿里云镜像下载. 下载地址:http://mirrors.aliyun.com/docker-toolbox/mac/docker-for-mac/stable/D ...
- DDCA —— 缓存一致性
1. 多处理器内存组织结构 1.1 SMP/集中式共享内存 集中式共享内存多处理器(Centralized shared-memory multiprocessor)或对称共享内存多处理器(Symme ...
- 超实用的SpringAOP实战之日志记录
本文主要以日志记录作为切入点,来讲解Spring AOP在实际项目开发中怎样更好的使项目业务代码更加简洁.开发更加高效. 日志处理只是AOP其中一种应用场景,当你掌握了这一种场景,对于其它应用场景也可 ...
- VulnStack之ATT&CK实战系列———红队实战(一)
目录 前言 环境搭建 外围打点 信息收集 phpmyadmin全局日志getshell 内网信息收集 msf上线 mimikatz抓取明文密码&hash 域信息收集 横向移动 msf+prox ...