diff --git a/control/navbutton/navbutton.cpp b/control/navbutton/navbutton.cpp index d1000fb..67c7e4e 100644 --- a/control/navbutton/navbutton.cpp +++ b/control/navbutton/navbutton.cpp @@ -46,7 +46,11 @@ NavButton::NavButton(QWidget *parent) : QPushButton(parent) setText("导航按钮"); } +#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0)) +void NavButton::enterEvent(QEnterEvent *) +#else void NavButton::enterEvent(QEvent *) +#endif { hover = true; this->update(); diff --git a/control/navbutton/navbutton.h b/control/navbutton/navbutton.h index 37a221d..b9a43b4 100644 --- a/control/navbutton/navbutton.h +++ b/control/navbutton/navbutton.h @@ -92,7 +92,11 @@ public: explicit NavButton(QWidget *parent = 0); protected: +#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0)) + void enterEvent(QEnterEvent *); +#else void enterEvent(QEvent *); +#endif void leaveEvent(QEvent *); void paintEvent(QPaintEvent *); void drawBg(QPainter *painter); diff --git a/docs/video_system/index.html b/docs/video_system/index.html index f7e975d..0e7e9c5 100644 --- a/docs/video_system/index.html +++ b/docs/video_system/index.html @@ -201,87 +201,6 @@ mark .md-meta { color: rgb(0, 0, 0); } .md-inline-math-container mjx-container { zoom: 0.95; } -.CodeMirror { height: auto; } -.CodeMirror.cm-s-inner { background: inherit; } -.CodeMirror-scroll { overflow: auto hidden; z-index: 3; } -.CodeMirror-gutter-filler, .CodeMirror-scrollbar-filler { background-color: rgb(255, 255, 255); } -.CodeMirror-gutters { border-right: 1px solid rgb(221, 221, 221); background: inherit; white-space: nowrap; } -.CodeMirror-linenumber { padding: 0px 3px 0px 5px; text-align: right; color: rgb(153, 153, 153); } -.cm-s-inner .cm-keyword { color: rgb(119, 0, 136); } -.cm-s-inner .cm-atom, .cm-s-inner.cm-atom { color: rgb(34, 17, 153); } -.cm-s-inner .cm-number { color: rgb(17, 102, 68); } -.cm-s-inner .cm-def { color: rgb(0, 0, 255); } -.cm-s-inner .cm-variable { color: rgb(0, 0, 0); } -.cm-s-inner .cm-variable-2 { color: rgb(0, 85, 170); } -.cm-s-inner .cm-variable-3 { color: rgb(0, 136, 85); } -.cm-s-inner .cm-string { color: rgb(170, 17, 17); } -.cm-s-inner .cm-property { color: rgb(0, 0, 0); } -.cm-s-inner .cm-operator { color: rgb(152, 26, 26); } -.cm-s-inner .cm-comment, .cm-s-inner.cm-comment { color: rgb(170, 85, 0); } -.cm-s-inner .cm-string-2 { color: rgb(255, 85, 0); } -.cm-s-inner .cm-meta { color: rgb(85, 85, 85); } -.cm-s-inner .cm-qualifier { color: rgb(85, 85, 85); } -.cm-s-inner .cm-builtin { color: rgb(51, 0, 170); } -.cm-s-inner .cm-bracket { color: rgb(153, 153, 119); } -.cm-s-inner .cm-tag { color: rgb(17, 119, 0); } -.cm-s-inner .cm-attribute { color: rgb(0, 0, 204); } -.cm-s-inner .cm-header, .cm-s-inner.cm-header { color: rgb(0, 0, 255); } -.cm-s-inner .cm-quote, .cm-s-inner.cm-quote { color: rgb(0, 153, 0); } -.cm-s-inner .cm-hr, .cm-s-inner.cm-hr { color: rgb(153, 153, 153); } -.cm-s-inner .cm-link, .cm-s-inner.cm-link { color: rgb(0, 0, 204); } -.cm-negative { color: rgb(221, 68, 68); } -.cm-positive { color: rgb(34, 153, 34); } -.cm-header, .cm-strong { font-weight: 700; } -.cm-del { text-decoration: line-through; } -.cm-em { font-style: italic; } -.cm-link { text-decoration: underline; } -.cm-error { color: red; } -.cm-invalidchar { color: red; } -.cm-constant { color: rgb(38, 139, 210); } -.cm-defined { color: rgb(181, 137, 0); } -div.CodeMirror span.CodeMirror-matchingbracket { color: rgb(0, 255, 0); } -div.CodeMirror span.CodeMirror-nonmatchingbracket { color: rgb(255, 34, 34); } -.cm-s-inner .CodeMirror-activeline-background { background: inherit; } -.CodeMirror { position: relative; overflow: hidden; } -.CodeMirror-scroll { height: 100%; outline: 0px; position: relative; box-sizing: content-box; background: inherit; } -.CodeMirror-sizer { position: relative; } -.CodeMirror-gutter-filler, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-vscrollbar { position: absolute; z-index: 6; display: none; outline: 0px; } -.CodeMirror-vscrollbar { right: 0px; top: 0px; overflow: hidden; } -.CodeMirror-hscrollbar { bottom: 0px; left: 0px; overflow: auto hidden; } -.CodeMirror-scrollbar-filler { right: 0px; bottom: 0px; } -.CodeMirror-gutter-filler { left: 0px; bottom: 0px; } -.CodeMirror-gutters { position: absolute; left: 0px; top: 0px; padding-bottom: 10px; z-index: 3; overflow-y: hidden; } -.CodeMirror-gutter { white-space: normal; height: 100%; box-sizing: content-box; padding-bottom: 30px; margin-bottom: -32px; display: inline-block; } -.CodeMirror-gutter-wrapper { position: absolute; z-index: 4; background: 0px 0px !important; border: none !important; } -.CodeMirror-gutter-background { position: absolute; top: 0px; bottom: 0px; z-index: 4; } -.CodeMirror-gutter-elt { position: absolute; cursor: default; z-index: 4; } -.CodeMirror-lines { cursor: text; } -.CodeMirror pre { border-radius: 0px; border-width: 0px; background: 0px 0px; font-family: inherit; font-size: inherit; margin: 0px; white-space: pre; overflow-wrap: normal; color: inherit; z-index: 2; position: relative; overflow: visible; } -.CodeMirror-wrap pre { overflow-wrap: break-word; white-space: pre-wrap; word-break: normal; } -.CodeMirror-code pre { border-right: 30px solid transparent; width: fit-content; } -.CodeMirror-wrap .CodeMirror-code pre { border-right: none; width: auto; } -.CodeMirror-linebackground { position: absolute; inset: 0px; z-index: 0; } -.CodeMirror-linewidget { position: relative; z-index: 2; overflow: auto; } -.CodeMirror-wrap .CodeMirror-scroll { overflow-x: hidden; } -.CodeMirror-measure { position: absolute; width: 100%; height: 0px; overflow: hidden; visibility: hidden; } -.CodeMirror-measure pre { position: static; } -.CodeMirror div.CodeMirror-cursor { position: absolute; visibility: hidden; border-right: none; width: 0px; } -.CodeMirror div.CodeMirror-cursor { visibility: hidden; } -.CodeMirror-focused div.CodeMirror-cursor { visibility: inherit; } -.cm-searching { background: rgba(255, 255, 0, 0.4); } -span.cm-underlined { text-decoration: underline; } -span.cm-strikethrough { text-decoration: line-through; } -.cm-tw-syntaxerror { color: rgb(255, 255, 255); background-color: rgb(153, 0, 0); } -.cm-tw-deleted { text-decoration: line-through; } -.cm-tw-header5 { font-weight: 700; } -.cm-tw-listitem:first-child { padding-left: 10px; } -.cm-tw-box { border-style: solid; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-color: inherit; border-top-width: 0px !important; } -.cm-tw-underline { text-decoration: underline; } -@media print { - .CodeMirror div.CodeMirror-cursor { visibility: hidden; } -} - - :root { --side-bar-bg-color: #fafafa; --control-text-color: #777; @@ -674,11 +593,13 @@ header, .context-menu, .megamenu-content, footer{
使用说明
写法举例
V20220106
V20211220
V20211205
xxxxxxxxxx261void QUIStyle::getStyle(QStringList &styleNames, QStringList &styleFiles)2{3 static QStringList names;4 if (names.count() == 0) {5 names << "黑蓝色" << "软件黑" << "视频黑";6 names << "深黑色" << "深蓝色" << "深灰色";7 names << "扁平黑" << "扁平蓝" << "扁平灰";8 names << "浅黑色" << "浅蓝色" << "浅灰色";9 names << "普通黑" << "普通蓝" << "普通灰";10 names << "大蓝色" << "大紫色" << "大银色";11 }12
+https://pan.baidu.com/s/13LDRu6mXC6gaADtrGprNVA 提取码: ujm7。- 如果是64位的qt则对应的dll时候拷贝dll_ffmpeg4_64目录下的。
- 如果使用的ffmpeg3则对应dll目录就是dll_ffmpeg,在ffmpeg.pri文件中可以看到具体启用的是ffmpeg3(支持XP)还是ffmpeg4(不支持XP),默认是ffmpeg4。
- 如果编译运行提示miniblink文件不存在请先拷贝,则说明你当前用的Qt版本没有浏览器模块,要么没安装,要么不支持,你也不用担心啥,此时自动切换用的miniblink浏览器内核,你还需要将ffmpeg库下载的网盘的地方找到dll_miniblink.zip下载解压到可执行文件同一目录即可。
- 系统中所有的图标,都采用的图形字体,对照表在doc目录下的FontAwesome.png、FontAliBaBa.png,对应图形字体类IconHelper中加载的图形字体,后期如果还有增加的其他图形字体也是放在这里,一个类支持多种图形字体,通过不同的值范围自动设置。
- 如果发现地图打不开或者提示秘钥文件丢失,请先确认file目录下的所有文件有没有拷贝过去。
- 如果是用vs+qt可能报错 error LNK2026,解决办法详细见文档中其他说明。
- 默认用户名admin 密码admin。
- 系统配置参数在加载的时候会对节点值进行过滤判断,如果为空会自动用初始值生成新的配置文件,如果不想要显示版权所有公司,可以填xxx而不是删掉整个值。
- 如果是用vlc推流的rtsp地址,比如 rtsp://:8554/aabb,由于vlc推流默认写死的采用的udp协议,所以监控系统也必须在系统设置中通信方式选择udp才行(默认tcp)。
0.6.3 离线地图
- 离线地图可以用网上的瓦片地图下载器下载百度的离线地图放到对应目录即可。
- 也可以直接下载网盘中已经下载好的上海市的离线地图。
- 下载地址:https://pan.baidu.com/s/1d7TH_GEYl5nOecuNlWJJ7g 提取密码:01jf 文件名称:bin_map_tiles.zip
使用说明
- 将压缩包下的两个文件夹复制到对应可执行文件下的config文件夹下,和map.js文件同一级目录。
- tiles文件夹是街道图,tiles_hybrid文件夹是卫星图。
- 默认提供的是上海市徐汇区的瓦片地图,如果自己用万能地图下载器下载的百度地图的瓦片文件,也可以对应替换就行。
- 要注意的是格式,默认是jpg,如果下载的瓦片地图格式是png则需要打开config文件夹下的map_load.js文件,将.jpg改成.png保存即可。
0.7 视频格式
0.7.1 USB摄像头
- 内核ffmpeg写法:video=USB2.0 PC CAMERA(具体要看设备名)。
- 内核vlc写法:dshow://:dshow-vdev=Default (或者填USB2.0 PC CAMERA)
- 带参数写法:2020-12-12以后增加USB摄像头直接url带分辨率帧率写法,默认分辨率640x480。
写法举例
- video=USB2.0 PC CAMERA|1920x1080|30(表示1920*1080分辨率30帧)
- video=USB2.0 PC CAMERA|640x480(表示640*480分辨率)
- dshow://:dshow-vdev=USB2.0 PC CAMERA(表示打开视频设备USB2.0 PC CAMERA、其他参数全部默认)
- dshow://:dshow-vdev=USB2.0 PC CAMERA:dshow-adev=麦克风 (USB Audio Device):dshow-size=1920*1080:live-caching=300(表示打开视频设备USB2.0 PC CAMERA、打开音频设备麦克风 (USB Audio Device)、分辨率640x480、缓存时间300毫秒)
0.7.2 网络地址
- 下面的地址有时候会失效,可以自行网上找找其他的地址,网络视频地址建议在晚上测试会更流畅。
- 大雄兔:rtsp://184.72.239.149/vod/mp4://BigBuckBunny_175k.mov
- 大雄兔:http://r.ossrs.net/live/bbb.flv
- 海康萤石:https://hls01open.ys7.com/openlive/6e0b2be040a943489ef0b9bb344b96b8.hd.m3u8
- 在线摄像机:http://vts.simba-cn.com:280/gb28181/21100000001320000002.m3u8
- 摄像机格式:https://blog.csdn.net/qq_38880380/article/details/80652697
0.7.3 中央卫视
- 中央卫视1:rtmp://58.200.131.2:1935/livetv/cctv1
- 中央卫视2:rtmp://58.200.131.2:1935/livetv/cctv2
- 中央卫视3:rtmp://58.200.131.2:1935/livetv/cctv3
- 中央卫视4:rtmp://58.200.131.2:1935/livetv/cctv4
- 中央卫视5:rtmp://58.200.131.2:1935/livetv/cctv5
- 中央卫视6:rtmp://58.200.131.2:1935/livetv/cctv6
- 中央卫视7:rtmp://58.200.131.2:1935/livetv/cctv7
- 中央卫视8:rtmp://58.200.131.2:1935/livetv/cctv8
- 中央卫视9:rtmp://58.200.131.2:1935/livetv/cctv9
- 中央卫视10:rtmp://58.200.131.2:1935/livetv/cctv10
0.7.4 视频文件
万能办法,用谷歌或者谷歌内核的浏览器,打开时光网http://www.mtime.com/ ,随便打开个视频,这里一般是预告片,按F12切换到审查元素,顶部切换到网络,选中媒体,刷新网页,按照尺寸排列,最大的那个MP4文件就是,鼠标右键复制地址,这个地址就是完整的网络地址。
+ 
- http://vfx.mtime.cn/Video/2019/02/04/mp4/190204084208765161.mp4
- http://vfx.mtime.cn/Video/2019/03/19/mp4/190319212559089721.mp4
- http://vfx.mtime.cn/Video/2019/03/17/mp4/190317150237409904.mp4
- http://vfx.mtime.cn/Video/2019/03/14/mp4/190314223540373995.mp4
0.7.5 网友提供
- rtmp://live.yihtc.com:10935/hls/stream_3
- rtmp://live.yihtc.com:10935/hls/stream_13
- rtmp://218.3.205.46/live/ggpd_sd
- rtmp://hls.hsrtv.cn/hls/hstv2
- rtmp://hls.hsrtv.cn/hls/hstv1
- rtmp://222.173.22.119:1935/live/jnyd_sd
- rtmp://222.173.22.119:1935/live/xwhd_hd
- rtmp://livetv.dhtv.cn:1935/live/peoples
- rtmp://livetv.dhtv.cn:1935/live/citylife
- rtmp://livetv.dhtv.cn:1935/live/financial
- rtmp://livetv.dhtv.cn:1935/live/news
0.8 版本说明
0.8.1 精益求精
0.8.2 破茧成蝶
考虑增加mediaplayer内核,限定Qt5.有些嵌入式板子支持mediaplay硬解码。
+V20220106
- 彻底修复全屏模式+webengine同时存在的情况下鼠标右键菜单无法弹出以及视频可能黑屏的BUG,这是Qt的BUG。
- 同时测试多屏幕下正常状态和全屏状态的情况,多屏幕不同分辨率。
- 增加其他设置界面,将串口设置、网络设置等移动到其他设置。随着功能越来越多,也很有必要单独拆分设置。
- 修复打印预览看不到文字的BUG,原来是设置了QGraphicsView的前景色导致的,把前景色和背景色设置成一样的了,其实是有文字的,鬼想得到QPrintPreviewDialog里面的预览原来用的是QGraphicsView绘制的。
- 修复qchart图表控件鼠标按下松开后会跟随窗体移动的BUG,因为qchart鼠标按下是UngrabMouse事件而不是MouseButtonRelease。
- 修复表格行按下后自定义委托颜色在部分样式方案下设置不正确的BUG。
- 增加视频弹窗按钮,封装的统一的视频弹窗静态函数,直接传入url地址即可。
- 修复鼠标按下视频预览底部工具栏也能拖曳视频的BUG。
- 海康内核解析增加对通道的解析,比如可能是一个摄像机有多个通道,或者NVR多个通道。同时完善主码流子码流的解析,可以解析多个码流,之前只能解析主码流子码流两个。
- 海康内核句柄模式下增加等比例缩放自适应。
- onvif模块修复部分厂家摄像机比如天地伟业,搜索返回的媒体地址等一系列请求地址,没有加onvif节点的BUG。
V20211220
- 重新梳理整个onvif模块,调整对应的结构,删除多余的变量和设置等,对应云台控制等操作需要指定profile,通过参数传入。
- 对应图片参数操作需要指定videosource,通过参数传入。
- 去除数据库字段mediaurl、ptzurl,因为这两个数据每次都是更新重新获取的,通过getServices获取,这两个字段改成了videosource、profiletoken,用来从数据库读取出来,每次使用的时候自动下发。
- 预置位表格中的按钮样式调整,去掉圆角,增加边距,效果更完美。
- 新增nvr多个通道onvif支持,改动onvif模块代码和数据库结构。
- 搜索设备后判断是否多个videosource,多个表示有多个视频源,一般是NVR,也有部分IPC自带多个视频源。
- 有多个则根据不同厂家不同规则,找出对应的每个通道的videosource、profiletoken、rtspmain、rtspsub用分隔符 | 插入到临时表格中。
- 摄像机管理界面接收到添加设备的时候,在addDevice槽函数中,判断发过来的数据,带了 | 要分别取出来作为通道添加到数据库中。
- 重新定义搜索的摄像机设备命名规则,按照摄像机#ip地址末尾数字的方式。
- 如果是NVR过来的摄像机,增加自动查找NVR的名称插入数据库。
- 获取预置位增加立即清空所有行,之前是先清空内容再根据读取到的预置位个数设置行数。
- 增加双击打开NVR(也叫分组)对应策略 0-最后空白通道 1-从头清空通道。
- 增加双击打开IPC(也叫设备)对应策略 0-最后空白通道 1-最后按下通道。
- 改进在分辨率不同缩放比例保持一致的UI体验,不受缩放比例的影响。
- 修正异或加密,增加对@String开头的密文进行过滤,防止高版本产生的配置文件到低版本的Qt程序不能正确解析的BUG。
- 如果打开视频流出错提示 Server returned 5XX Server Error reply 表示摄像机的码流满了,可能多个地方在拉取码流导致摄像机输出的视频流被占满,已经没有更多资源。
V20211205
- 地图内核增加了海量点接口。
- 路径规划模块彻底重写,支持重新绘制、沿线移动等模式,数据表格显示。
- 设备轨迹模块改成从gps点集合文本文件加载进行循环动态模拟移动,默认飞机图标,以便转动角度。
- 设备播放增加保存视频开关配置参数,可以直接在界面上开启,开启后,通过rtsp从nvr取流比如回放视频,可以将回放的视频保存MP4文件到本地。
- 修正Qt6通过属性设置标签labtip不能居中对齐的BUG。
- 封装通用的设置一堆按钮比如添加、删除、保存、导入、导出等按钮图形字体的函数,直接传入父面板即可,自动查找对应的objname设置图标,省去一堆重复代码。
- 新增飞行轨迹模块frmDeviceGps2,之前的frmDeviceGps作为通过外部函数调用移动。
- 样式统一整理规范,分类6大类:normal、black、light、dark、flat、other。
x1void QUIStyle::getStyle(QStringList &styleNames, QStringList &styleFiles)2{3 static QStringList names;4 if (names.count() == 0) {5 names << "黑蓝色" << "软件黑" << "视频黑";6 names << "深黑色" << "深蓝色" << "深灰色";7 names << "扁平黑" << "扁平蓝" << "扁平灰";8 names << "浅黑色" << "浅蓝色" << "浅灰色";9 names << "普通黑" << "普通蓝" << "普通灰";10 names << "大蓝色" << "大紫色" << "大银色";11 }12
13 //中文皮肤名称对应样式表文件14 static QStringList files;15 if (files.count() == 0) {16 files << ":/qss/blackblue.css" << ":/qss/blacksoft.css" << ":/qss/blackvideo.css";17 files << ":/qss/darkblack.css" << ":/qss/darkblue.css" << ":/qss/darkgray.css";18 files << ":/qss/flatblack.css" << ":/qss/flatblue.css" << ":/qss/flatgray.css";19 files << ":/qss/lightblack.css" << ":/qss/lightblue.css" << ":/qss/lightgray.css";20 files << ":/qss/normalblack.css" << ":/qss/normalblue.css" << ":/qss/normalgray.css";21 files << ":/qss/otherblue.css" << ":/qss/otherpurple.css" << ":/qss/othersilvery.css";22 }23
24 styleNames = names;25 styleFiles = files;26}
V20211111
- ONVIF组件增加图片参数范围获取,之前默认0-255,有些设备是0-100 0-128之类的,获取后设置到滑动条范围。
- ONVIF组件增加网络参数设置,比如IP地址,子网掩码、网关地址、DNS设置等。
- ONVIF组件将结构体定义统一移到一个头文件onvifstruct.h,方便后期拓展管理。
- 预置位模块,调用、添加(调用)、删除三种功能,改成了以三个按钮的形式加到每个预置位信息的后面直接单击使用。之前是先选中预置位所在行,然后单击下面的按钮。
- 通道轮询全部移动单独的悬停的模块。
- 视频面板窗体指针改成了全局变量,多处需要引用。
- 修复1通道轮询后,再次启动程序无法正确加载通道面板布局的BUG。
- 修复底部通道切换,部分样式效果悬停时候颜色不正确的BUG。改成了取报警图标颜色和已处理颜色。
- 路径规划模块增加模拟轨迹设备自动旋转角度移动。
- 路径规划模块模拟轨迹增加移动间隔下拉框选择。
- 修复Qt4对应webkit模块不支持返回数组的问题,改成字符串拼接用 ; 符隔开。
- 修复Qt4对应webkit模块不支持路径规划的BUG,因为开启了实时路况属性。
- 路径规划增加绘制实时轨迹线条,不同颜色显示。
V20211101
- 修正开启轮询后关闭所有视频通道不弹出提示信息。
- 所有信息框增加阴影边框区分突出显示,并跟随系统换肤自动更新边框阴影。
- 修正视频轮询分隔符,将|改成;因为如果是竖杠遇到带有参数的url则会出错。
- 将设备图片统一存放到config/device目录,之前在config目录下,随着越来越多非常凌乱。
- 修复之前通过信号执行通道切换,对应文字显示反了的BUG(通道1交换到通道2,新的通道2应该显示之前通道1的文本)。
- 将鼠标按下两个通道交换的处理代码,复用信号槽切换通道的函数。
- 将视频监控布局切换部分单独提取类VideoBox,专门负责管理各种通道布局切换,复用代码并且方便后期拓展,这部分代码和具体的处理无关,一直以来就想要单独提取出来进行管理,后期可以方便的增加其他异形布局以及255通道布局等,很多项目都用到了这个切换逻辑。
- 同时增加了布局切换子菜单比如13画面子菜单切换到52_64通道。
- 修复Qt6中视频控件悬浮条无法显示的BUG,因为Qt6将void enterEvent(QEvent *);改成了void enterEvent(QEnterEvent *);也不打个招呼。这种改变编译也不会提示的。
- 数据库组件修正sqlserver数据库必须设置数据源的不足,改成了dsn字符串形式,不需要新建数据源也能直接通信。
- 数据库组件修正mysql数据库必须存在默认数据库mysql的不足,改成了不需要默认数据库也能正常通信。
- 数据库组件修正没有默认数据库也能在建立连接后新建数据库操作。
- 数据库脚本执行将DROP DATABASE IF EXIST改成了DROP DATABASE ,这样无论什么时候都能先删除原来的数据库然后再新建数据库CREATE DATABASE。有些数据库不支持IF EXIST。
V20211005
- 修正ffmpeg内核,在播放地址不存在的情况下,打开容易卡主引起崩溃的BUG,在打开回调函数中增加对线程停止标志位的判断,一旦在打开的回调中识别到需要停止线程则立即返回结束。
- 增加临时信息中间弹出框提示信息,比如一次性关闭所有通道的时候,界面会卡主的期间提示。
- 增加忙碌鼠标图标切换显示,忙完以后自动恢复鼠标样式。
- 修正ffmpeg内核,开始时间记录可能出现问题的BUG,会导致部分特殊MP4文件打不开。
- 应用程序关闭,增加全局退出信号关联到视频通道管理类,先关闭所有视频通道再彻底退出应用程序。不这样处理的话,发现vlc内核在开启了视频存储的时候,会关不掉程序。
- 修复在没有声音播放的情况下主动调用停止播放造成崩溃的BUG。
- 修复在linux系统上QUIWidget弹出的无边框窗体带系统标题栏的BUG。
- 修复ffmpeg内核关闭视频后opengl窗体来不及隐藏的BUG。
- 修复重复立即刷新打开所有通道,前一次还没执行后一次又来了的BUG,改成了定时器处理,在立即执行前将上一次还没来得及执行的先停止。
- 增加about关于对话框窗体,显示版本号、版权所有、网址、电话等信息。
- 所有弹出窗体都跟随软件主窗体默认居中,这个特性非常棒。
- 所有皮肤增加右键菜单选中图标样式、右键菜单二级子菜单右侧小三角箭头图标样式,单选框、复选框、禁用状态图标全部更新,从图形字体绘制,极其统一舒服。
- 着重对日志类savelog增加了最大行数、最大文件大小等参数设置,可以设置按照行数或者大小来自动分割日志文件。
- 日志类增加了可过滤不同的消息类型,不同消息类型增加消息头。
- 经过大量对比测试发现,使用miniblink浏览器内核,容易卡,说不定什么时候就失效了,问题集中在32位,64位的目前没有发现这个现象,webengine暂时没有这个现象,但是加载打开摄像机的网页配置,还是miniblink更优秀。
- 中文标题栏支持换行,既可以副标题写在英文标题上,也可以同等大小字体写在中文标题上。
V20210922
- 视频控件边框增加0像素选项,这样看起来没有边框,有些场景需要无缝拼接。
- 修复当采用NVR通道作为摄像机视频流显示的时候,ONVIF处理索引越界崩溃的情况,因为一台NVR同一个IP地址对应多个摄像机。
- 所有样式17套皮肤更新边框颜色。
- 系统信息增加对应的编译器名字、位数、版本等。
- 演示demo增加视频叠加演示功能,比如在主视频的左上角、右上角、左下角、右下角在增加一个视频缩略图显示。
- 新增天气预报模块,可设置城市、采集间隔、展示样式等。
- 增加了vlc内核下USB摄像头格式自动纠正,如果采用ffmpeg的格式video=USB2.0 PC CAMERA|1920x1080自动纠正。
- 纠正vlc内核下USB摄像头不自动拉伸的BUG。
- 修正vlc内核动态保存视频文件,文件命名不符合规范,重新按照设定的重命名。
- 修复vlc内核中USB摄像头会当做rtsp视频流的BUG。
- 天气预报模块新增城市显示,新增双击弹出天气预报设置,含打印信息。
- 系统信息,增加秘钥文件的内容,比如允许的设备数量、到期日期等。
- 修复配置文件一旦新增加节点,之前节点全部初始值运行的BUG,应该是存在的节点则读取节点值,不存在的节点以初始值运行。
V20210705
- 改进窗体居中显示算法,可设置参照窗体,默认基于当前屏幕中心,可设置参照主窗体则基于参照窗体,在大分辨率屏幕效果非常好,不然主窗体很小,弹个窗找不到还在很远的地方,还以为没有弹呢。
- 将登陆窗体、登出窗体、用户管理等公用界面,做成了通用库core_form。
- 修复MAC系统上无边框窗体无法最小化的BUG。
- 增加超级管理员密码A具有所有权限的机制,避免管理员误将系统设置权限取消后无法再次进去系统设置的问题。
- 图片参数增加锐度,图片参数设置滑块调节松开立即设置。
- 修复当没有启用图片地图的时候对应界面隐藏的时候保存设备坐标位置报错BUG,因为没有启用的情况下没有设置对应的对象指针。
V20210603
- 将onvif搜索的用户密码,设备播放界面的设备密码等配置参数全部改成了密文存储。
- 大量修改代码,全部支持Qt4-Qt6所有版本。
- 调整onvif代码执行机制,改成了异步执行。
- 云台协议增加了连续移动。
- 增加了预置位相关处理,包括获取预置位、调用预置位、添加预置位、删除预置位。
- 自动巡航按照预置位集合进行,采用定时器去调用预置位队列。
- 增加图文警情行数、窗口信息行数配置,0行表示自动处理。
- 做了大量的代码改进,比如onvif内核换成了QDom对象处理,之前是采用的QXmlQuery查询,由于XmlPatterns这个模块逐渐废弃了,而且在Qt6中不再有,所以彻底移除了XmlPatterns相关的代码,改用其他处理方式实现。
- 增加了预置位和自动巡航处理,其中包括获取预置位集合、调用预置位、添加预置位、删除预置位、设置起始位、调用起始位等。
- ONVIF内核几乎全部重写,将数据改成了结构体,比如设备信息、预置位信息、事件信息等,可以存储更多的数据,拓展也非常灵活。
- onvif处理部分增加了对非onvif设备的过滤,通过判断是否存在onvif地址。这样可以大大加快处理速度,打开视频的时候去实例化onvif通信,关闭视频的时候删除对应的onvif类,这样可以动态响应。
- 所有onvif指令改成了线程处理,处理完成一个立马处理下一个,排队处理。
V20210425
- 配置文件密码改成密文存储。
- 增加了无敌的牛逼的万能的完美入微级自动分页导航控件。
- 日志记录表增加索引,速度提升100倍以上。
- 新增多个设备轨迹 不同颜色+传入经纬度 单独示例。
- 对地图核心类所有覆盖物都增加颜色+粗细+透明度的参数,可动态传入对应值。
- 系统设置增加用户管理模块,可分别设置对应的权限。
- 万能权限管理算法,通过设置不同需要授权的模块名称,对应切换的按钮自动计算。
- 增加了appkey秘钥类,用于校验秘钥是否正确,运行时间等。
V20210403
- 增加全局变量AppData::LastLiveTime,记住程序最后的活动时间-包括键盘+鼠标活动,用于两个判断,一个是超过多久没有操作全屏下隐藏鼠标光标,一个是超过多久没有操作如果没有全屏则自动全屏。
- 增加App::TimeAutoFull配置参数用来判断比较超时自动全屏。
- 重命名为TimeHideCursor表示程序多久未操作自动隐藏光标,TimeAutoFull程序多久未操作自动全屏界面,下拉框选项值增加0,表示不启用此功能。
- 增加信息列表模块frmMsgList,用于图文列表显示信息,对应兄弟类frmMsgTable用于表格显示消息。
- 大改版,将中间部分全部改成了QMainWindow,子模块全部采用停靠窗体,可以悬浮半透明,自动记忆每个模块的最后的位置,启动后自动应用。
- 移除大改版后的所有不需要用的变量和配置参数,重新调整配置参数。
- 增加透明度参数用于停靠窗体独立出来后的透明度。
- 将摄像机控制部分比如云台+控制+预置位+巡航,单独分类到ipc模块,方便管理。
- 限定操作员不能移动停靠窗体等,需要管理员设计好。
- 修复系统设置中工作模式等切换造成的自动重启会弹出退出和登录两个窗体的BUG。
- 修复自动登录用户计算不正确的BUG,要以最后登录的用户为准。
V20210322
- USB摄像头增加参数帧率,第二个参数是分辨率,第三个参数为帧率,不设置则采用默认的帧率,video=USB2.0 PC CAMERA|1920x1080|25。
- 增加独立的demo模块,专门用于测试监控系统中用到的组件和控件,演示如何使用,比如视频图片界面演示从文件夹读取图片绘制到窗体,视频窗体演示系统的核心组件视频控件的设置参数如何使用等。
- 增加了对其他数据库的支持,比如posgres、oracle、odbc、kingbase等数据库,理论上只要支持odbc数据源方式的都支持。
- 增加IndexStart启动窗体索引配置参数,0-主程序 1-演示示例。
V20210305
- 修复数据库有时候没加载到的BUG。
- 新增配置参数控制画面切换的菜单和快捷图标是否显示。
- ffmpeg内核增加了可动态保存机制,点击开始保存按钮启动保存,单击结束则生成视频文件,如此往复。
- 海康内核判断主码流子码流改成了 /101? 和 /main/ 同时判断。
- 新增多屏幕的支持,自动在对应屏幕最大化全屏,对话框位置,右下角提示框等。
- 再次分类存放代码文件,分成core ui class三大类。
- 系统配置更改视频控件参数,统一一个函数设置,initCommonVideoWidget函数中做了过滤,必须关闭状态的视频控件设置才起作用。
- 设备播放模块增加大华NVR的远程回放地址,其他地址计算算法调整。
- 新增界面模块功能启用配置参数。
- 新增主界面顶部导航模块中间界面,用于不同的运行模式加载不同的模块。
0.8.3 快速迭代
V20201212
- 增加USB摄像机分辨率设置,直接url带掉。
- 所有地图内核公用一个,复用代码。
- 增加地图默认级别和中心点坐标设置参数。
- 主界面四个模块独立出来,做成了可配置,这样后期可以任意位置放置自定义模块。
- 四个模块标题栏自定义。
- vlc内核和mpv内核的离线判断,当句柄模式下,统一为getLastTime,当调用该函数的时候自动查询播放状态,如果正在播放则自动更新时间为当前时间。
- 将各种在代码中define定义不同内核的代码全部优化,统一为一个类,很大减少代码量,统一为CommonVideoWidget和CommonVideoManage类。
V20201108
- 轮询点模块增加批量生成功能。
- 录像机、摄像机、轮询点,增加导入导出功能。
- ffmpeg内核增加读取帧回调,超时识别,可以快速识别掉线。
20200828
- 增加了云台控制过滤,没有打开的视频禁用云台。
- linux上全屏BUG修复,采用showfullscreen。
- 增加轮询点管理模块。
- 修正轮询的可能崩溃的BUG。
V20200730
- 系统设置增加了视频上传模块,用来将本地的视频文件传输到服务器,多线程并发。
- 视频监控内核新增MPV内核,修正了其他内核的部分函数和处理。
- 海康内核进行大改动,同时支持视频流和本地MP4文件播放,自动分析切换。
- 海康内核增加回调处理,可以拿到每一张图片。
- 海康内核进行了linux上的实验,可以正常播放。
- ffmpeg内核增加保存到MP4。
- 本地文件回放vlc部分增加进度切换等。
- 悬浮条关闭按钮增加实际处理,之前只是打印消息。
- 改进了vlc和mpv的事件回调机制,使其同时支持qt4+qt5。
V20200620
- 增加了opengl显示实时视频,CPU占用极低。
- 增加了地图上设备点位置的调整。
- 设备点双击弹出实时视频预览。
- 增加GPS运动轨迹显示。
- ffmpeg解码类增加了音频播放,采用的QAudioOutput。
V20191105
- 增加云台控制功能,可以上下左右等八个方位控制云台,默认采用相对移动,云台中间按下表示复位。
- 系统设置增加码流类型选择,默认子码流,切换完自动应用。
- 云台控制增加速度功能,值越大,速度越快。
- 增加焦距控制,可放大缩小,速度也可控制。
1 用户登录退出
1.1 用户登录
@@ -805,7 +726,7 @@ header, .context-menu, .megamenu-content, footer{
不仅分文件夹存放的,而且命名也尽量按照对应功能打头,比如系统设置模块中的都用frmconfig打头,外层文件夹是整齐的,内部代码也是整齐的。
名称 说明 frmconfig 系统设置模块,包括基本设置、录像机管理、摄像机管理、轮询管理、用户管理、视频上传等。 frmdata 日志查询模块,包括本地日志、设备日志等。 frmdemo 演示demo示例,用于演示具体控件或者功能的使用,方便学习参考,比如视频图片、视频控件、视频存储都单独的使用demo。 frmipc 存放摄像机处理相关的模块,比如设备控制,云台控制、预置位、巡航设置等。之前放在frmmodule模块中,后面独立出来管理更方便。 frmmain 主界面模块,包括登录登出界面、主界面、右上角时间组件、欢迎组件等。 frmmap 地图模块,包括通用地图内核界面、图片地图、在线地图、离线地图、路径规划等。 frmmodule 停靠子窗体模块,包括停靠窗体管理核心类、设备列表、窗口信息、图文警情、设备轨迹、网页浏览等模块。将摄像机、机器人、无人机相关的模块放到了对应的模块文件夹,这里放的是系统通用的模块。 frmrobot 无人机模块,包括图像增强、飞行监控等模块。 frmuavs 无人机模块,包括图像增强、飞行监控等模块。 frmvideo 视频监控模块,所有视频监控相关的都放在这里,包括主界面的视频监控布局窗体、视频回放、远程回放、图片回放等。
11.3.4.1 模块-frmconfig
名称 说明 frmconfig 系统设置模块主界面,采用堆栈窗体形式,加载多个子界面比如摄像机管理、轮询管理等。 frmconfigdb 数据库设置,独立出来,很多系统通用。 frmconfigipc 摄像机管理,可以增加、删除、修改、清空、导入、导出、打印摄像机信息。 frmconfigipcsearch onvif设备搜索,独立出来的窗体,可以搜索局域网内的所有onvif摄像机信息,搜索完以后获取摄像机的视频流地址等,最后可以单个添加或者批量选中添加到摄像机信息表格中。 frmconfignvr 录像机管理,可以增加、删除、修改、清空、导入、导出、打印录像机信息。 frmconfigpoll 轮询管理,可以增加、删除、修改、清空、导入、导出、打印轮询点信息。可以按照设定规则批量生成轮询点信息。 frmconfigpollplus 将轮询管理中的轮询参数配置、分组管理、批量添加等独立出来的界面,方便管理和拓展。 frmconfigsave 录像计划,目前空的,等想好了怎么设计好在实现。 frmconfigsystem 系统设置,包括基本设置、视频参数、数据库设置、地图配置、功能激活、颜色配置、串口配置、网络配置等。 frmconfiguser 用户管理,可以增加、删除、修改、清空、导入、导出、打印用户信息。每个用户可以勾选不同的模块权限。
11.3.4.2 模块-frmdata
名称 说明 frmdata 日志查询模块主界面,采用堆栈窗体形式,加载多个子界面包括本地日志、设备日志等。 frmdatadevice 设备日志,通过私有协议从NVR取对应设备日志信息。 frmdatauser 本地地址,用户操作的日志信息,可查询和导出打印数据记录。
11.3.4.3 模块-frmdemo
名称 说明 frmdemo 单独的功能演示示例主窗体,加载多个子界面比如视频控件等。 frmdemovideoimage 视频图片示例,从图片文件夹读取图片集合,定时器绘制取出图片发给视频控件绘制。 frmdemovideosave 视频保存示例,演示如何对视频控件进行视频保存,可动态保存。 frmdemovideowidget 视频控件示例,演示视频控件如何使用。
11.3.4.4 模块-frmipc
名称 说明 frmipccontrol 设备控制模块,可对选中设备进行图片参数调节、NTP校时、设备重启、抓拍图片(ONVIF抓图)等。 frmipcnavigate 巡航管理模块,暂未实现,后期完善。 frmipcreset 预置位管理模块,暂未实现,后期完善。 frmipcptz 云台控制模块,可对选中的摄像机进行云台控制。
11.3.4.5 模块-frmmain
名称 说明 frmlogin 用户登录界面,三次错误关闭,下拉可选用户,内置超级密码。 frmlogout 用户退出界面,三次错误关闭,下拉可选用户,内置超级密码。 frmmain 系统主界面,采用堆栈窗体,加载各个子模块。 frmmain1 备用模块1界面,根据参数设置决定是否启用。 frmtimecpu 右上角日期时间+CPU内存显示。 frmwelcome 右上角欢迎信息界面。
11.3.4.6 模块-frmmap
名称 说明 frmmap 地图管理主界面,采用堆栈窗体形式,加载各个子界面比如图片地图、在线地图、离线地图、路径规划等。 frmmapcore 通用百度地图内核界面,用来加载百度地图,可设置在线、离线模式,有很多个窗体用到类似功能特意封装到一个类,重复利用,比如悬浮地图、飞行轨迹、路径规划等模块都用到了此内核。 frmmapdevice 通用的设备地图界面,在线地图和离线地图界面公用这个界面,唯一区别就是设置下地图的模式是在线还是离线。 frmmapimage 图片地图界面,设备作为一个个按钮点显示在对应地图上,可以拖动,双击弹出预览实时视频。 frmmaplocal 离线地图界面,可更新经纬度值、模拟运动轨迹等。 frmmapweb 在线地图界面,可更新经纬度值、模拟运动轨迹等。 frmmaproute 路径规划界面,可查询路线得到路线的经纬度坐标集合。
11.3.4.7 模块-frmmodule
名称 说明 frmdevicegps 设备轨迹模块,对设定的设备随机模拟轨迹,也可传入经纬度坐标值自动移动并绘制轨迹线条,不同设备可以不同颜色。 frmdevicetree 设备列表模块,读取设备信息加载形成树状列表,双击或者拖动到视频监控窗体直接播放视频,提供右键菜单作为演示如何使用。 frmmodule 主界面中心部分窗体,采用QMainWindow类,中间加载的视频监控面板,其余new出来每个子模块,子模块可停靠和悬浮拖动等。不同工作模式下的各种子模块都在此加载。同时负责管理模块的显示隐藏菜单。 frmmsglist 图文警情模块,也叫消息列表模块,带有右键菜单添加、删除、清空列表中的消息,双击可以弹出大图预览。 frmmsglistitem 图文警情模块子类,都是由一个个item组成放到panelwidget面板控件中,自动形成滚动条。 frmmsgtable 窗口消息模块,也叫表格消息模块,表格形式显示打印信息,不同的内容可以不同颜色区分。 frmwebview 网页浏览模块,传入一个url地址打开对应的网页,比如打开一个3D的网页。
11.3.4.8 模块-frmrobot
名称 说明 frmrobotdata 仿真数据模块,启动机器人通信服务,接收数据解析显示。 frmrobotdebug 数据调试模块,可模拟发送轨迹数据测试解析类。 frmrobotdebug2 新数据调试模块,打印多个串口数据,不同颜色显示。 frmrobotemulate 运动仿真模块,预留给用户实现,一般放个3D效果。 frmrobotlog 机器人实时数据模块,预留给用户实现。
11.3.4.9 模块-frmuavs
名称 说明 frmuavsflight 飞行套件控件面板,放了多个飞行仪表,默认自动模拟数据,可以传入对应数据显示。 frmuavsimage 图像增强模块,预留给用户实现。 frmuavspanel 飞行监控面板。
11.3.4.10 模块-frmvideo
名称 说明 frmvideo 视频回放模块主界面,堆栈窗体形式,加载多个子界面比如本地回放、远程回放、设备播放等。 frmvideopanel 视频监控面板,主界面中间部分,这是核心,管理多个通道,通道可移除删除,拖曳打开,拖曳交换等。 frmvideopaneltool 视频监控底部工具栏,独立出来一个类专门管理。 frmvideoplayimage 图片回放模块,按照规则查询图片目录,然后可设定播放速度进行图片序列播放。 frmvideoplaylocal 本地回放模块,查询对应通道的本地存储的视频文件,双击播放,可暂停和拖动进度条位置。 frmvideoplaynvr 设备播放模块,通过RTSP视频流的形式从远程设备取视频进行播放,支持摄像机和录像机,手动填入地址也行。 frmvideoplayweb 远程回放模块,需要用厂家sdk去实现,从NVR回放录像。 frmvideopreview 视频预览窗体,比如图片或者地图上双击设备弹出的视频预览,可以多个,关闭的时候自动释放资源。 frmvideoupload 视频上传,将本地存储的视频文件上传到服务器。
12 二次开发说明
12.1 开发环境搭建
12.1.1 常规通用步骤
- 第一步:安装系统,推荐用vmware虚拟机。
- 第二步:安装qt环境,可以直接用官方下载的run安装包安装,有些要求用命令行安装。
- 第三步:写个空白窗体程序测试下是否环境正常。
- 第四步:编译ffmpeg,生成对应的动态库或者静态库。
- 第五步:打开video_system.pro项目进行编译。
- 第六步:打包发布,为了发布方便,推荐用静态编译的Qt+静态编译的ffmpeg,这样打包发布很清爽,就一个可执行文件。
12.1.2 windows+mingw
12.1.3 windows+msvc
12.1.4 linux+ubuntu
12.1.5 linux+deepin
12.1.6 linux+centeros
12.1.7 linux+uos
12.1.8 linux+银河麒麟
12.2 通用模块使用
12.3 人工智能集成
13 其他说明
13.1 海康onvif设置
新版的海康的摄像机,默认onvif是关闭的,需要手动开启,开启以后记得添加onvif用户,并重启摄像机应用。提示:海康旗下的萤石目前暂时不支持onvif协议。
13.2 大华onvif设置
大华摄像机,需要在用户管理中添加onvif用户,添加好以后建议重启摄像机应用。
13.3 国际onvif工具
- 工具的名字叫ONVIF Device Manager,可以自行搜索下载,此工具位国际官方工具,如果此工具搜索不到摄像机,则说明该摄像机不是真正的onvif摄像机,不是标准的摄像机,目前市面上的绝大部分网络摄像机都支持onvif。
+ 工具的名字叫ONVIF Device Manager,可以自行搜索下载,此工具位国际官方工具,如果此工具搜索不到摄像机,则说明该摄像机不是真正的onvif摄像机,不是标准的摄像机,目前市面上的绝大部分网络摄像机都支持onvif。具体用法可以参考 https://www.cnblogs.com/lsdb/p/9157302.html
现在大部分厂家的NVR也逐渐支持onvif,并将每个通道都可以单独列出来。
13.4 报警输入设置
- 默认摄像机IO输入或者开关量输入是关闭的,需要手动开启。
- 一般都是登录到摄像机的web页面找到开关量的地方,可能描述不一样但是大致的意思差不多。
- 一般摄像机会有两组开关量输入,而且开关量报警有常开常闭两种,都需要自己手动选择。
- 如果是常开的话意味着闭合是属于报警,反之亦然。
- 找两个导线接在对应口子(详见摄像机厂家的说明书,摄像机背面板也会有对应字样标识一般叫 in)。
- 短接或者扒开,都会有反应,onvif工具都能接收到信息(前提是单击过订阅事件按钮,而且顺利返回了订阅地址才行)。
- 会收到LogicalState关键字的信息,true或者1表示报警,false或者0表示正常。
- 可能每个厂家会有所区别,需要自己拿到数据后做特殊处理,但是大部分厂家都是相似的,实在不行无非搞个contains方法判断好了。
diff --git a/docs/video_system/snap/0-7-4.jpg b/docs/video_system/snap/0-7-4.jpg
new file mode 100644
index 0000000..baa2b32
Binary files /dev/null and b/docs/video_system/snap/0-7-4.jpg differ
diff --git a/ui/core_common/appdata.cpp b/ui/core_common/appdata.cpp
index 04b5888..b760576 100644
--- a/ui/core_common/appdata.cpp
+++ b/ui/core_common/appdata.cpp
@@ -1,22 +1,22 @@
#include "appdata.h"
#include "quihelper.h"
-QString AppData::Version = "V20211105";
+QString AppData::Version = "V20220316";
QString AppData::TitleFlag = "(QQ: 517216493 WX: feiyangqingyun)";
int AppData::RowHeight = 25;
int AppData::RightWidth = 180;
-int AppData::FormWidth = 950;
-int AppData::FormHeight = 650;
+int AppData::FormWidth = 1200;
+int AppData::FormHeight = 750;
void AppData::checkRatio()
{
//根据分辨率设定宽高
int width = QUIHelper::deskWidth();
- if (width > 1440) {
+ if (width >= 1440) {
RowHeight = RowHeight < 25 ? 25 : RowHeight;
RightWidth = RightWidth < 220 ? 220 : RightWidth;
- FormWidth = FormWidth < 1250 ? 1250 : FormWidth;
- FormHeight = FormHeight < 850 ? 850 : FormHeight;
+ FormWidth = FormWidth < 1200 ? 1200 : FormWidth;
+ FormHeight = FormHeight < 800 ? 800 : FormHeight;
}
}
diff --git a/ui/core_common/core_common.pri b/ui/core_common/core_common.pri
index b2628da..bb0827e 100644
--- a/ui/core_common/core_common.pri
+++ b/ui/core_common/core_common.pri
@@ -1,3 +1,4 @@
+QT += network
#指定编译产生的文件分门别类放到对应目录
MOC_DIR = temp/moc
RCC_DIR = temp/rcc
@@ -34,6 +35,15 @@ SOURCES += \
$$PWD/iconhelper.cpp \
$$PWD/quihelper.cpp
-RESOURCES += $$PWD/qrc/qm.qrc
-RESOURCES += $$PWD/qrc/font.qrc
+#可以指定不加载对应的资源文件
+!contains(DEFINES, no_qrc_image) {
RESOURCES += $$PWD/qrc/image.qrc
+}
+
+!contains(DEFINES, no_qrc_qm) {
+RESOURCES += $$PWD/qrc/qm.qrc
+}
+
+!contains(DEFINES, no_qrc_font) {
+RESOURCES += $$PWD/qrc/font.qrc
+}
diff --git a/ui/core_common/quihelper.cpp b/ui/core_common/quihelper.cpp
index 2b3eabf..10da70b 100644
--- a/ui/core_common/quihelper.cpp
+++ b/ui/core_common/quihelper.cpp
@@ -1,5 +1,7 @@
#include "quihelper.h"
+#include "qnetworkinterface.h"
+#define TIMEMS qPrintable(QTime::currentTime().toString("HH:mm:ss zzz"))
int QUIHelper::getScreenIndex()
{
//需要对多个屏幕进行处理
@@ -57,6 +59,11 @@ int QUIHelper::deskHeight()
return getScreenRect().height();
}
+QSize QUIHelper::deskSize()
+{
+ return getScreenRect().size();
+}
+
QWidget *QUIHelper::centerBaseForm = 0;
void QUIHelper::setFormInCenter(QWidget *form)
{
@@ -77,6 +84,18 @@ void QUIHelper::setFormInCenter(QWidget *form)
form->move(movePoint);
}
+void QUIHelper::showForm(QWidget *form)
+{
+ setFormInCenter(form);
+ form->show();
+
+ //判断宽高是否超过了屏幕分辨率,超过了则最大化显示
+ //qDebug() << TIMEMS << form->size() << deskSize();
+ if (form->width() + 20 > deskWidth() || form->height() + 50 > deskHeight()) {
+ QMetaObject::invokeMethod(form, "showMaximized", Qt::QueuedConnection);
+ }
+}
+
QString QUIHelper::appName()
{
//没有必要每次都获取,只有当变量为空时才去获取一次
@@ -86,6 +105,7 @@ QString QUIHelper::appName()
//下面的方法主要为了过滤安卓的路径 lib程序名_armeabi-v7a
QStringList list = name.split("/");
name = list.at(list.count() - 1).split(".").at(0);
+ name.replace("_armeabi-v7a", "");
}
return name;
@@ -93,12 +113,164 @@ QString QUIHelper::appName()
QString QUIHelper::appPath()
{
+ static QString path;
+ if (path.isEmpty()) {
#ifdef Q_OS_ANDROID
- //return QString("/sdcard/Android/%1").arg(appName());
- return QString("/storage/emulated/0/%1").arg(appName());
+ //path = QString("/sdcard/Android/%1").arg(appName());
+ path = QString("/storage/emulated/0/%1").arg(appName());
#else
- return qApp->applicationDirPath();
+ path = qApp->applicationDirPath();
#endif
+ }
+
+ return path;
+}
+
+QStringList QUIHelper::getLocalIPs()
+{
+ static QStringList ips;
+ if (ips.count() == 0) {
+#ifdef Q_OS_WASM
+ ips << "127.0.0.1";
+#else
+ QList netInterfaces = QNetworkInterface::allInterfaces();
+ foreach (const QNetworkInterface &netInterface, netInterfaces) {
+ //移除虚拟机和抓包工具的虚拟网卡
+ QString humanReadableName = netInterface.humanReadableName().toLower();
+ if (humanReadableName.startsWith("vmware network adapter") || humanReadableName.startsWith("npcap loopback adapter")) {
+ continue;
+ }
+
+ //过滤当前网络接口
+ bool flag = (netInterface.flags() == (QNetworkInterface::IsUp | QNetworkInterface::IsRunning | QNetworkInterface::CanBroadcast | QNetworkInterface::CanMulticast));
+ if (!flag) {
+ continue;
+ }
+
+ QList addrs = netInterface.addressEntries();
+ foreach (QNetworkAddressEntry addr, addrs) {
+ //只取出IPV4的地址
+ if (addr.ip().protocol() != QAbstractSocket::IPv4Protocol) {
+ continue;
+ }
+
+ QString ip4 = addr.ip().toString();
+ if (ip4 != "127.0.0.1") {
+ ips << ip4;
+ }
+ }
+ }
+#endif
+ }
+
+ return ips;
+}
+
+QList QUIHelper::colors = QList();
+QList QUIHelper::getColorList()
+{
+ //备用颜色集合 可以自行添加
+ if (colors.count() == 0) {
+ colors << QColor(0, 176, 180) << QColor(0, 113, 193) << QColor(255, 192, 0);
+ colors << QColor(72, 103, 149) << QColor(185, 87, 86) << QColor(0, 177, 125);
+ colors << QColor(214, 77, 84) << QColor(71, 164, 233) << QColor(34, 163, 169);
+ colors << QColor(59, 123, 156) << QColor(162, 121, 197) << QColor(72, 202, 245);
+ colors << QColor(0, 150, 121) << QColor(111, 9, 176) << QColor(250, 170, 20);
+ }
+
+ return colors;
+}
+
+QStringList QUIHelper::getColorNames()
+{
+ QList colors = getColorList();
+ QStringList colorNames;
+ foreach (QColor color, colors) {
+ colorNames << color.name();
+ }
+ return colorNames;
+}
+
+QColor QUIHelper::getRandColor()
+{
+ QList colors = getColorList();
+ int index = getRandValue(0, colors.count(), true);
+ return colors.at(index);
+}
+
+void QUIHelper::initRand()
+{
+ //初始化随机数种子
+ QTime t = QTime::currentTime();
+ srand(t.msec() + t.second() * 1000);
+}
+
+float QUIHelper::getRandFloat(float min, float max)
+{
+ double diff = fabs(max - min);
+ double value = (double)(rand() % 100) / 100;
+ value = min + value * diff;
+ return value;
+}
+
+double QUIHelper::getRandValue(int min, int max, bool contansMin, bool contansMax)
+{
+ int value;
+#if (QT_VERSION <= QT_VERSION_CHECK(5,10,0))
+ //通用公式 a是起始值,n是整数的范围
+ //int value = a + rand() % n;
+ if (contansMin) {
+ if (contansMax) {
+ value = min + 0 + (rand() % (max - min + 1));
+ } else {
+ value = min + 0 + (rand() % (max - min + 0));
+ }
+ } else {
+ if (contansMax) {
+ value = min + 1 + (rand() % (max - min + 0));
+ } else {
+ value = min + 1 + (rand() % (max - min - 1));
+ }
+ }
+#else
+ if (contansMin) {
+ if (contansMax) {
+ value = QRandomGenerator::global()->bounded(min + 0, max + 1);
+ } else {
+ value = QRandomGenerator::global()->bounded(min + 0, max + 0);
+ }
+ } else {
+ if (contansMax) {
+ value = QRandomGenerator::global()->bounded(min + 1, max + 1);
+ } else {
+ value = QRandomGenerator::global()->bounded(min + 1, max + 0);
+ }
+ }
+#endif
+ return value;
+}
+
+QStringList QUIHelper::getRandPoint(int count, float mainLng, float mainLat, float dotLng, float dotLat)
+{
+ //随机生成点坐标
+ QStringList points;
+ for (int i = 0; i < count; ++i) {
+ //0.00881415 0.000442928
+#if (QT_VERSION >= QT_VERSION_CHECK(5,10,0))
+ float lngx = QRandomGenerator::global()->bounded(dotLng);
+ float latx = QRandomGenerator::global()->bounded(dotLat);
+#else
+ float lngx = getRandFloat(dotLng / 10, dotLng);
+ float latx = getRandFloat(dotLat / 10, dotLat);
+#endif
+ //需要先用精度转换成字符串
+ QString lng2 = QString::number(mainLng + lngx, 'f', 8);
+ QString lat2 = QString::number(mainLat + latx, 'f', 8);
+ QString point = QString("%1,%2").arg(lng2).arg(lat2);
+ points << point;
+ }
+
+ return points;
}
QString QUIHelper::getUuid()
@@ -109,13 +281,6 @@ QString QUIHelper::getUuid()
return uuid;
}
-void QUIHelper::initRand()
-{
- //初始化随机数种子
- QTime t = QTime::currentTime();
- srand(t.msec() + t.second() * 1000);
-}
-
void QUIHelper::newDir(const QString &dirName)
{
QString strDir = dirName;
@@ -151,30 +316,69 @@ void QUIHelper::sleep(int msec)
void QUIHelper::setStyle()
{
//打印下所有内置风格的名字
- qDebug() << "Qt内置的样式" << QStyleFactory::keys();
+ qDebug() << TIMEMS << "QStyleFactory::keys" << QStyleFactory::keys();
+ //设置内置风格
#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0))
qApp->setStyle(QStyleFactory::create("Fusion"));
#else
qApp->setStyle(QStyleFactory::create("Cleanlooks"));
#endif
- //qApp->setPalette(QPalette("#FFFFFF"));
+
+ //设置指定颜色
+ QPalette palette;
+ palette.setBrush(QPalette::Window, QColor("#F0F0F0"));
+ qApp->setPalette(palette);
+}
+
+QFont QUIHelper::addFont(const QString &fontFile, const QString &fontName)
+{
+ //判断图形字体是否存在,不存在则加入
+ QFontDatabase fontDb;
+ if (!fontDb.families().contains(fontName)) {
+ int fontId = fontDb.addApplicationFont(fontFile);
+ QStringList listName = fontDb.applicationFontFamilies(fontId);
+ if (listName.count() == 0) {
+ qDebug() << QString("load %1 error").arg(fontName);
+ }
+ }
+
+ //再次判断是否包含字体名称防止加载失败
+ QFont font;
+ if (fontDb.families().contains(fontName)) {
+ font = QFont(fontName);
+#if (QT_VERSION >= QT_VERSION_CHECK(4,8,0))
+ font.setHintingPreference(QFont::PreferNoHinting);
+#endif
+ }
+
+ return font;
}
void QUIHelper::setFont(int fontSize)
{
- QFont font;
- font.setFamily("MicroSoft Yahei");
-#ifdef Q_OS_ANDROID
- font.setPixelSize(15);
-#elif __arm__
- font.setPixelSize(25);
-#else
- font.setPixelSize(fontSize);
+#ifdef rk3399
+ return;
+#endif
+ //安卓套件在有些手机上默认字体不好看需要主动设置字体
+ //网页套件需要主动加载中文字体才能正常显示中文
+#if (defined Q_OS_ANDROID) || (defined Q_OS_WASM)
+ QString fontFile = ":/font/DroidSansFallback.ttf";
+ QString fontName = "Droid Sans Fallback";
+ qApp->setFont(addFont(fontFile, fontName));
+ return;
#endif
-#ifndef rk3399
- qApp->setFont(font);
+#ifdef __arm__
+ fontSize = 25;
#endif
+#ifdef Q_OS_ANDROID
+ fontSize = 15;
+#endif
+
+ QFont font;
+ font.setFamily("MicroSoft Yahei");
+ font.setPixelSize(fontSize);
+ qApp->setFont(font);
}
void QUIHelper::setCode(bool utf8)
@@ -205,26 +409,99 @@ void QUIHelper::setTranslator(const QString &qmFile)
}
QTranslator *translator = new QTranslator(qApp);
- translator->load(qmFile);
- qApp->installTranslator(translator);
+ if (translator->load(qmFile)) {
+ qApp->installTranslator(translator);
+ }
}
-void QUIHelper::initAll()
+void QUIHelper::initAll(bool utf8, bool style, int fontSize)
{
//初始化随机数种子
QUIHelper::initRand();
- //设置样式风格
- QUIHelper::setStyle();
- //设置字体
- QUIHelper::setFont(13);
//设置编码
- QUIHelper::setCode();
+ QUIHelper::setCode(utf8);
+ //设置样式风格
+ if (style) {
+ QUIHelper::setStyle();
+ }
+ //设置字体
+ QUIHelper::setFont(fontSize);
//设置翻译文件支持多个
QUIHelper::setTranslator(":/qm/widgets.qm");
QUIHelper::setTranslator(":/qm/qt_zh_CN.qm");
QUIHelper::setTranslator(":/qm/designer_zh_CN.qm");
}
+void QUIHelper::initMain(bool on)
+{
+ //设置是否应用操作系统设置比如字体
+ QApplication::setDesktopSettingsAware(on);
+
+#ifdef Q_OS_ANDROID
+#if (QT_VERSION >= QT_VERSION_CHECK(5,6,0))
+ //开启高分屏缩放支持
+ QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
+#endif
+#else
+#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0))
+ //不应用任何缩放
+ QApplication::setAttribute(Qt::AA_Use96Dpi);
+#endif
+#endif
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5,14,0))
+ //高分屏缩放策略
+ QApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::Floor);
+#endif
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5,4,0))
+ //设置opengl模式 AA_UseDesktopOpenGL(默认) AA_UseOpenGLES AA_UseSoftwareOpenGL
+ //在一些很旧的设备上或者对opengl支持很低的设备上需要使用AA_UseOpenGLES表示禁用硬件加速
+ //如果开启的是AA_UseOpenGLES则无法使用硬件加速比如ffmpeg的dxva2
+ //QApplication::setAttribute(Qt::AA_UseOpenGLES);
+ //设置opengl共享上下文
+ QApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
+#endif
+}
+
+QVector QUIHelper::msgTypes = QVector() << 0 << 1 << 2 << 3 << 4;
+QVector QUIHelper::msgKeys = QVector() << "发送" << "接收" << "解析" << "错误" << "提示";
+QVector QUIHelper::msgColors = QVector() << QColor("#3BA372") << QColor("#EE6668") << QColor("#9861B4") << QColor("#FA8359") << QColor("#22A3A9");
+QString QUIHelper::appendMsg(QTextEdit *textEdit, int type, const QString &data, int maxCount, int ¤tCount, bool clear, bool pause)
+{
+ if (clear) {
+ textEdit->clear();
+ currentCount = 0;
+ return QString();
+ }
+
+ if (pause) {
+ return QString();
+ }
+
+ if (currentCount >= maxCount) {
+ textEdit->clear();
+ currentCount = 0;
+ }
+
+ //不同类型不同颜色显示
+ QString strType;
+ int index = msgTypes.indexOf(type);
+ if (index >= 0) {
+ strType = msgKeys.at(index);
+ textEdit->setTextColor(msgColors.at(index));
+ }
+
+ //过滤回车换行符
+ QString strData = data;
+ strData.replace("\r", "");
+ strData.replace("\n", "");
+ strData = QString("时间[%1] %2: %3").arg(TIMEMS).arg(strType).arg(strData);
+ textEdit->append(strData);
+ currentCount++;
+ return strData;
+}
+
void QUIHelper::setFramelessForm(QWidget *widgetMain, bool tool, bool top, bool menu)
{
widgetMain->setProperty("form", true);
@@ -292,6 +569,102 @@ int QUIHelper::showMessageBoxQuestion(const QString &info)
//return QMessageBox::question(0, "询问", info, QMessageBox::Yes | QMessageBox::No);
}
+void QUIHelper::initDialog(QFileDialog *dialog, const QString &title, const QString &acceptName,
+ const QString &dirName, bool native, int width, int height)
+{
+ //设置标题
+ dialog->setWindowTitle(title);
+ //设置标签文本
+ dialog->setLabelText(QFileDialog::Accept, acceptName);
+ dialog->setLabelText(QFileDialog::Reject, "取消(&C)");
+ dialog->setLabelText(QFileDialog::LookIn, "查看");
+ dialog->setLabelText(QFileDialog::FileName, "名称");
+ dialog->setLabelText(QFileDialog::FileType, "类型");
+
+ //设置默认显示目录
+ if (!dirName.isEmpty()) {
+ dialog->setDirectory(dirName);
+ }
+
+ //设置对话框宽高
+ if (width > 0 && height > 0) {
+#ifdef Q_OS_ANDROID
+ bool horizontal = (QUIHelper::deskWidth() > QUIHelper::deskHeight());
+ if (horizontal) {
+ width = QUIHelper::deskWidth() / 2;
+ height = QUIHelper::deskHeight() - 50;
+ } else {
+ width = QUIHelper::deskWidth() - 10;
+ height = QUIHelper::deskHeight() / 2;
+ }
+#endif
+ dialog->setFixedSize(width, height);
+ }
+
+ //设置是否采用本地对话框
+ dialog->setOption(QFileDialog::DontUseNativeDialog, !native);
+ //设置只读可以取消右上角的新建按钮
+ //dialog->setReadOnly(true);
+}
+
+QString QUIHelper::getDialogResult(QFileDialog *dialog)
+{
+ QString result;
+ if (dialog->exec() == QFileDialog::Accepted) {
+ result = dialog->selectedFiles().first();
+ }
+ return result;
+}
+
+QString QUIHelper::getOpenFileName(const QString &filter, const QString &dirName, const QString &fileName,
+ bool native, int width, int height)
+{
+ QFileDialog dialog;
+ initDialog(&dialog, "打开文件", "选择(&S)", dirName, native, width, height);
+
+ //设置文件类型
+ if (!filter.isEmpty()) {
+ dialog.setNameFilter(filter);
+ }
+
+ //设置默认文件名称
+ dialog.selectFile(fileName);
+ return getDialogResult(&dialog);
+}
+
+QString QUIHelper::getSaveFileName(const QString &filter, const QString &dirName, const QString &fileName,
+ bool native, int width, int height)
+{
+ QFileDialog dialog;
+ initDialog(&dialog, "保存文件", "保存(&S)", dirName, native, width, height);
+
+ //设置文件类型
+ if (!filter.isEmpty()) {
+ dialog.setNameFilter(filter);
+ }
+
+ //设置默认文件名称
+ dialog.selectFile(fileName);
+ //设置模态类型允许输入
+ dialog.setWindowModality(Qt::WindowModal);
+ //设置置顶显示
+ dialog.setWindowFlags(dialog.windowFlags() | Qt::WindowStaysOnTopHint);
+ return getDialogResult(&dialog);
+}
+
+QString QUIHelper::getExistingDirectory(const QString &dirName, bool native, int width, int height)
+{
+ QFileDialog dialog;
+ initDialog(&dialog, "选择目录", "选择(&S)", dirName, native, width, height);
+ dialog.setOption(QFileDialog::ReadOnly);
+ //设置只显示目录
+#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
+ dialog.setFileMode(QFileDialog::DirectoryOnly);
+#endif
+ dialog.setOption(QFileDialog::ShowDirsOnly);
+ return getDialogResult(&dialog);
+}
+
QString QUIHelper::getXorEncryptDecrypt(const QString &value, char key)
{
//矫正范围外的数据
@@ -299,7 +672,12 @@ QString QUIHelper::getXorEncryptDecrypt(const QString &value, char key)
key = 127;
}
+ //大概从5.9版本输出的加密密码字符串前面会加上 @String 字符
QString result = value;
+ if (result.startsWith("@String")) {
+ result = result.mid(8, result.length() - 9);
+ }
+
int count = result.count();
for (int i = 0; i < count; i++) {
result[i] = QChar(result.at(i).toLatin1() ^ key);
@@ -331,6 +709,8 @@ uchar QUIHelper::getCheckCode(const QByteArray &data)
void QUIHelper::initTableView(QTableView *tableView, int rowHeight, bool headVisible, bool edit, bool stretchLast)
{
+ //设置弱属性用于应用qss特殊样式
+ tableView->setProperty("model", true);
//取消自动换行
tableView->setWordWrap(false);
//超出文本不显示省略号
@@ -374,7 +754,8 @@ void QUIHelper::openFile(const QString &fileName, const QString &msg)
#ifdef __arm__
return;
#endif
- if (fileName.isEmpty()) {
+ //文件不存在则不用处理
+ if (!QFile(fileName).exists()) {
return;
}
if (QUIHelper::showMessageBoxQuestion(msg + "成功!确定现在就打开吗?") == QMessageBox::Yes) {
@@ -401,8 +782,10 @@ bool QUIHelper::checkIniFile(const QString &iniFile)
QStringList list = line.split("=");
if (list.count() == 2) {
- if (list.at(1) == "") {
- qDebug() << "ini node no value" << list.at(0);
+ QString key = list.at(0);
+ QString value = list.at(1);
+ if (value.isEmpty()) {
+ qDebug() << TIMEMS << "ini node no value" << key;
ok = false;
break;
}
diff --git a/ui/core_common/quihelper.h b/ui/core_common/quihelper.h
index dc40547..9a0216a 100644
--- a/ui/core_common/quihelper.h
+++ b/ui/core_common/quihelper.h
@@ -13,29 +13,66 @@ public:
//获取桌面宽度高度+居中显示
static int deskWidth();
static int deskHeight();
+ static QSize deskSize();
//居中显示窗体
//定义标志位指定是以桌面为参照还是主程序界面为参照
static QWidget *centerBaseForm;
static void setFormInCenter(QWidget *form);
+ static void showForm(QWidget *form);
//程序文件名称+当前所在路径
static QString appName();
static QString appPath();
- //获取uuid+初始化随机数种子+新建目录+延时
- static QString getUuid();
+ //获取本地网卡IP集合
+ static QStringList getLocalIPs();
+
+ //获取内置颜色集合
+ static QList colors;
+ static QList getColorList();
+ static QStringList getColorNames();
+ //随机获取颜色集合中的颜色
+ static QColor getRandColor();
+
+ //初始化随机数种子
static void initRand();
+ //获取随机小数
+ static float getRandFloat(float min, float max);
+ //获取随机数,指定最小值和最大值
+ static double getRandValue(int min, int max, bool contansMin = false, bool contansMax = false);
+ //获取范围值随机经纬度集合
+ static QStringList getRandPoint(int count, float mainLng, float mainLat, float dotLng, float dotLat);
+
+ //获取uuid
+ static QString getUuid();
+ //可执行文件目录下新建目录
static void newDir(const QString &dirName);
+ //延时
static void sleep(int msec);
- //设置样式+字体+编码+居中+翻译
+ //设置Qt自带样式
static void setStyle();
- static void setFont(int fontSize = 12);
+ //设置字体
+ static QFont addFont(const QString &fontFile, const QString &fontName);
+ static void setFont(int fontSize = 12);
+ //设置编码
static void setCode(bool utf8 = true);
+ //设置翻译文件
static void setTranslator(const QString &qmFile);
//一次性设置所有
- static void initAll();
+ static void initAll(bool utf8 = true, bool style = true, int fontSize = 13);
+
+ //初始化main函数最前面执行的一段代码
+ static void initMain(bool on = true);
+
+ //插入消息
+ static QVector msgTypes;
+ static QVector msgKeys;
+ static QVector msgColors;
+ static QString appendMsg(QTextEdit *textEdit, int type, const QString &data,
+ int maxCount, int ¤tCount,
+ bool clear = false, bool pause = false);
//设置无边框
static void setFramelessForm(QWidget *widgetMain, bool tool = false, bool top = false, bool menu = true);
@@ -49,6 +86,26 @@ public:
//弹出询问框
static int showMessageBoxQuestion(const QString &info);
+ //为什么还要自定义对话框因为可控宽高和汉化对应文本等
+ //初始化对话框文本
+ static void initDialog(QFileDialog *dialog, const QString &title, const QString &acceptName,
+ const QString &dirName, bool native, int width, int height);
+ //拿到对话框结果
+ static QString getDialogResult(QFileDialog *dialog);
+ //选择文件对话框
+ static QString getOpenFileName(const QString &filter = QString(),
+ const QString &dirName = QString(),
+ const QString &fileName = QString(),
+ bool native = false, int width = 900, int height = 600);
+ //保存文件对话框
+ static QString getSaveFileName(const QString &filter = QString(),
+ const QString &dirName = QString(),
+ const QString &fileName = QString(),
+ bool native = false, int width = 900, int height = 600);
+ //选择目录对话框
+ static QString getExistingDirectory(const QString &dirName = QString(),
+ bool native = false, int width = 900, int height = 600);
+
//异或加密-只支持字符,如果是中文需要将其转换base64编码
static QString getXorEncryptDecrypt(const QString &value, char key);
//异或校验
diff --git a/widget/lunarcalendarwidget/lunarcalendaritem.cpp b/widget/lunarcalendarwidget/lunarcalendaritem.cpp
index a003656..e49e40e 100644
--- a/widget/lunarcalendarwidget/lunarcalendaritem.cpp
+++ b/widget/lunarcalendarwidget/lunarcalendaritem.cpp
@@ -44,7 +44,11 @@ LunarCalendarItem::LunarCalendarItem(QWidget *parent) : QWidget(parent)
hoverBgColor = QColor(204, 183, 180);
}
+#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
+void LunarCalendarItem::enterEvent(QEnterEvent *)
+#else
void LunarCalendarItem::enterEvent(QEvent *)
+#endif
{
hover = true;
this->update();
diff --git a/widget/lunarcalendarwidget/lunarcalendaritem.h b/widget/lunarcalendarwidget/lunarcalendaritem.h
index de3e56e..4a18ea9 100644
--- a/widget/lunarcalendarwidget/lunarcalendaritem.h
+++ b/widget/lunarcalendarwidget/lunarcalendaritem.h
@@ -62,7 +62,11 @@ public:
explicit LunarCalendarItem(QWidget *parent = 0);
protected:
+#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
+ void enterEvent(QEnterEvent *);
+#else
void enterEvent(QEvent *);
+#endif
void leaveEvent(QEvent *);
void mousePressEvent(QMouseEvent *);
void mouseReleaseEvent(QMouseEvent *);