QML实现文件十六进制数据展示

前言

将一个二进制文件直接拖放到Qt Creator中可以直接查看到以十六进制显示的数据格式,如:
在这里插入图片描述
要实现一个这样的效果,还是要花不少时间的。

在网上找了挺多示例,其中一个开源代码效果不错(参考这里),但是是在QWidget中实现的,通过继承QAbstractScrollArea来实现数据滚动绘制。

如果QML中要自定义在paint中绘制,需要继承QQuickPaintedItem,那要实现这样的滚动分页展示就比较麻烦了。尝试了一下直接将Widget中实现的效果封装一下放到QML中去使用,就会比较省事,毕竟原有的开源效果已经做得很好了。
以此思路,开搞!!!

先来看效果:
在这里插入图片描述
这是在QML项目中实现的,中间的数据展示部分是使用QHexView代码Widget实现的。


本文demo 点击下载


正文

将Widget嵌入到QML中使用,先来看会遇到什么问题。

上面说到,QML中要自定义在paint中绘制,需要继承QQuickPaintedItem,然后重写paint函数,而QML Scene Graph场景图绘制是在两个不同的线程中,这个在Qt帮助文档中有说明:
在这里插入图片描述
也就是说,paint()不是从主GUI线程调用的,而是从启用GL的渲染器线程调用的.。

那这会带来什么问题呢,继续看
由于主UI框架是用QML做的,我们想把Widget嵌入到QML中使用,就需要新建一个类继承QQuickPaintedItem然后把Widget放到其中,封装起来后将该类通过qmlRegisterType注册交给QML去引用。那Widget窗口中的各种事件就需要从QML这边发送过去,所以需要进行一次事件转发,也就是说将QQuickPaintedItem获得的事件合理的转发给QWidget让QWidget能处理对应的消息。这个可以通过在QQuickPaintedItem中过滤事件后进行转发。
而UI渲染是在paint中调用widget的rander进行,我们知道Widget中UI渲染是在主线程,上面讲到 QQuickPaintedItem中的paint()不是从主GUI线程调用的,而是从启用GL的渲染器线程调用的,所以这样调用就会出现断言报错:

 "Cannot send events to objects owned by a different thread. Current thread 0x0x24f6d9d9db0. Receiver ''....

好在我们可以直接用Release模式规避这个断言,没办法,只能这样搞了,也只有这种方式能实现这种非常规的调用。

继承QQuickPaintedItem封装的关键代码:

HexViewItem::HexViewItem()
{this->setAcceptHoverEvents(true);this->setAcceptedMouseButtons(Qt::AllButtons);setFlag(ItemAcceptsInputMethod, true);setFlag(ItemIsFocusScope, true);setFlag(ItemHasContents, true);
}//不能在构造函数中调用
void HexViewItem::init()
{m_pHexContainer = new HexViewContainer();m_pHexContainer->init();qDebug() << __FUNCTION__ << "this size" << size();m_pHexContainer->resize(this->size().toSize());if(m_pHexContainer){m_pHexContainer->createWinId();m_pHexContainer->installEventFilter(this);QWindow* pw = (QWindow*)(window());pw->installEventFilter(this);this->update();}
}bool HexViewItem::sendEventToWidget(QEvent *e)
{if(!m_pHexContainer)return false;QWindow* wHandle = m_pHexContainer->windowHandle();bool res = false;if(wHandle){res = qApp->sendEvent(wHandle, e);}return res;
}void HexViewItem::paint(QPainter *painter)
{painter->save();if(m_pHexContainer){m_pHexContainer->render(painter);}painter->restore();
}bool HexViewItem::eventFilter(QObject *obj, QEvent *e)
{QWindow* pw = (QWindow*)(window());bool res = QQuickPaintedItem::eventFilter(obj, e);if(obj == m_pHexContainer){switch(e->type()){case QEvent::Paint:{QPaintEvent* pe = (QPaintEvent*)e;this->update(pe->rect());}break;}}else if(obj == pw){//* 如果是鼠标等(有鼠标坐标信息的事件。)的话我们得计算一下偏移量并修正一下,这里就只处理QMouseEvent和QWheelEvent作为示例//* 如果有其他类似的也需要修正,不然可能坐标偏移switch(e->type()){case QEvent::MouseButtonDblClick  :case QEvent::MouseButtonPress	  :case QEvent::MouseButtonRelease	  :case QEvent::MouseMove	          :case QEvent::MouseTrackingChange  :case QEvent::Move	              :{QMouseEvent *me = (QMouseEvent*)e;QEvent::Type type = me->type();QPointF localPosF = me->localPos();Qt::MouseButton mouseButton = me->button();Qt::MouseButtons mouseButtons = me->buttons();Qt::KeyboardModifiers modifiers = me->modifiers();//修正一下localposQPointF offsetF = mapToScene(QPoint(0,0));QPointF diffPosF = localPosF - offsetF;QMouseEvent tme(type, diffPosF, mouseButton, mouseButtons, modifiers);sendEventToWidget(&tme);}break;case QEvent::Wheel:{QWheelEvent *we = (QWheelEvent*)e;QPointF localPosF = we->posF();QPointF gloabalPosF = we->globalPosF();QPoint  pixelDelta = we->pixelDelta();QPoint  angleDelta = we->angleDelta();int qt4Delta = we->delta();Qt::Orientation orientation = we->orientation();Qt::MouseButtons mouseButtons = we->buttons();Qt::KeyboardModifiers modifiers = we->modifiers();//修正一下localposQPointF offsetF = mapToScene(QPoint(0,0));QPointF diffPosF = localPosF - offsetF;QWheelEvent twe(diffPosF, gloabalPosF, pixelDelta, angleDelta, qt4Delta, orientation, mouseButtons, modifiers);sendEventToWidget(&twe);}break;default:{
//             sendEventToWidget(e);}break;}}return res;
}void HexViewItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
{QQuickPaintedItem::geometryChanged(newGeometry, oldGeometry);if(m_pHexContainer){m_pHexContainer->setGeometry(newGeometry.toRect());}
}bool HexViewItem::event(QEvent *e)
{return __super::event(e);
}

关键点,将QQuickItem的窗口注册事件过滤器:

QWindow* pw = (QWindow*)(window());
pw->installEventFilter(this);

eventFilter就是过滤一些需要用到的关键事件进行转发,在paint()中调用Widget的render进行UI刷新。

QHexView源码进行过一些修改,添加了一些接口可供QML中快速设置,如:高亮某段数据、快速定位,头部底部对齐,主题切换,截图保存,切换展示宽度等

Q_INVOKABLE void setFilePath(int index, QString filePath);
Q_INVOKABLE void updateGeo();
Q_INVOKABLE void setSelect(int index,int pos,int len);
Q_INVOKABLE void closeFile(int index);  //关闭文件
Q_INVOKABLE void alignment(bool head,int index = -1);  //头部 尾部对齐
Q_INVOKABLE QStringList renderHexView(QList<int> fileIndexs);
Q_INVOKABLE void setTheme(bool darkTheme);
Q_INVOKABLE void setHexLineWidth(quint8 value);

可在此基础上进行扩展。

整体目录结构:
在这里插入图片描述


本文demo 点击下载


参考文章:
https://blog.csdn.net/r5014/article/details/92642626
https://github.com/Dax89/QHexView

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

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

相关文章

基于Python开发的飞机大战小游戏彩色版(源码+可执行程序exe文件+程序配置说明书+程序使用说明书)

一、项目简介 本项目是一套基于Python开发的飞机大战小游戏&#xff0c;主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的Python学习者。 包含&#xff1a;项目源码、项目文档等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调试&#xff0c;…

区块链实验室(20) - FISCO控制台连接到指定的节点

在FISCO技术文档中&#xff0c;控制台默认采用config.toml作为配置文件&#xff0c;并指定了连接的节点地址和商品&#xff0c;如下所示。 [network] peers["127.0.0.1:20200", "127.0.0.1:20201"] # The peer list to connect在该案例中&#xff0c;控…

【基础计算机网络1】认识计算机网络体系结构,了解计算机网络的大致模型(下)

前言 在上一篇我们主要介绍了有关计算机网络概述的内容&#xff0c;下面这一篇我们将来介绍有关计算机网络体系结构与参考模型的内容。这一篇博客紧紧联系上一篇博客。 这一篇博客主要内容是&#xff1a;计算机网络体系结构与参考模型&#xff0c;主要是计算机网络分层结构、协…

光学显微镜算法(OMA)(含MATLAB代码)

先做一个声明&#xff1a;文章是由我的个人公众号中的推送直接复制粘贴而来&#xff0c;因此对智能优化算法感兴趣的朋友&#xff0c;可关注我的个人公众号&#xff1a;启发式算法讨论。我会不定期在公众号里分享不同的智能优化算法&#xff0c;经典的&#xff0c;或者是近几年…

2023/9/7 -- C++/QT

作业 1> 思维导图 2> 封装一个结构体&#xff0c;结构体中包含一个私有数组&#xff0c;用来存放学生的成绩&#xff0c;包含一个私有变量&#xff0c;用来记录学生个数&#xff0c; 提供一个公有成员函数&#xff0c;void setNum(int num)用于设置学生个数 提供一个…

Python足球训练打卡系统SpringBoot足球场地预约系统源码 调试 lw

&#x1f495;&#x1f495;作者&#xff1a;计算机源码社 &#x1f495;&#x1f495;个人简介&#xff1a;本人七年开发经验&#xff0c;擅长Java、Python、PHP、.NET、微信小程序、爬虫、大数据等&#xff0c;大家有这一块的问题可以一起交流&#xff01; &#x1f495;&…

MySQL的故事——MySQL架构与历史

MySQL架构与历史 文章目录 MySQL架构与历史一、MySQL逻辑架构二、并发控制三、事务四、多版本并发控制(MVCC) 一、MySQL逻辑架构 第一层&#xff1a;连接处理、授权认证、安全等等 第二层&#xff1a;查询解析、分析、优化、缓存以及所有的内置函数。包含跨存储引擎的功能&…

双系统时间问题、虚拟机扩展空间问题

文献阅读计划&#xff1a; 首先要用ChatGPT查文献&#xff0c;用关键字查询&#xff0c;然后去搜索 add cyun 9.8 但是我发现好难搜啊&#xff0c;或者说相关的关键词搜不出来东西啊。不过师兄倒是搜的挺多的&#xff0c;这一点要再去好好学习一下 双系统时间问题&#xff1a…

SpringBoot整合Swagger3

前言 swagger是啥&#xff0c;是干什么的&#xff0c;有什么用&#xff0c;我想在这里我就不用介绍了&#xff0c;下面直接代码演示。 添加依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0…

Android 大图显示优化方案-加载Gif 自定义解码器

基于Glide做了图片显示的优化&#xff0c;尤其是加载Gif图的优化&#xff0c;原生Glide加载Gif图性能较低。在原生基础上做了自定义解码器的优化&#xff0c;提升Glide性能 Glide加载大图和Gif 尤其是列表存在gif时&#xff0c;会有明显卡顿&#xff0c;cpu和内存占用较高&…

【8章】Spark编程基础(Python版)

课程资源&#xff1a;&#xff08;林子雨&#xff09;Spark编程基础(Python版)_哔哩哔哩_bilibili 第8章 Spark MLlib&#xff08;6节&#xff09; 机器学习算法库 &#xff08;一&#xff09;MLlib简介 1、机器学习 机器学习可以看做是一门人工智能的科学&#xff0c;该领…

07-Spring Cloud

1、如何设计一个注册中心&#xff1f; 高可用&#xff1a;通过集群的方式 高并发&#xff1a;减少响应时间、提高吞吐量 并发用户数等&#xff0c;通过增加服务器性能、 扩展服务实例的方式 高性能&#xff1a;程序处理速度 考虑 数据存储结构、通信机制、集群同步。 集群…