Qt视图场景框架之SVG
来源:互联网 发布:经典书籍推荐知乎 编辑:程序博客网 时间:2024/06/13 14:33
Qt提供了对SVG图片的基本支持,对外提供了4个基本的类封装,支持SVG图片渲染展示,可以在GUI widget中和视图场景模型中加载使用SVG图片。由于Qt对SVG封装类较少提供的功能接口也较少,对于复杂的SVG操作还需要开发人员自己实现。另外,Qt只支持SVG 1.2 Tiny版本(SVG的一个子集标准),相对于浏览器对SVG标准的全量支持,Qt在渲染超出SVG1.2 Tiny版本的SVG图片是会出现问题,这也是在用Qt Svg开发过程中常见的问题而非Qt bug,所以在使用Qt Svg开发时要求SVG版本不能高于1.2 Tiny。Qt官方也暂无计划更新SVG模块,所以如果要使用的SVG图片版本较高,就只能考虑使用其他第三方类库或QtWebEngine来渲染实现了。
直接与SVG操作相关的类Qt只提供了4个:
QGraphicsSvgItem
QSvgGenerator
QSvgRenderer
QSvgWidget
这无疑满足不了我们复杂的需求开发,针对博主本人在开发过程中遇到的问题和解决方法总结如下:
1. 视图场景中SVG内部元素打散和重新组合
首先说组合,组合在视图场景中有两种通用实现方法:QGraphicsItemGroup方式和parentItem方式。
利用QGraphicsItemGroup比较简单,将Item添加到QGraphicsItemGroup中即可实现多个item组合,只需对 QGraphicsItemGroup这个Item操作即可。
auto group =scene->createItemGroup(scene->selecteditems());
scene->destroyItemGroup(group);
使用parentItrem方式,其实QGraphicsItemGroup就是对parentItrem方式的封装。
这里的SVG内部元素打散是说单独渲染绘制SVG内部元素,多个元素之间是独立显示。内部元素单独绘制显示有个限制,就是这个元素必须拥有唯一的id,QGraphicsSvgItem通过setElementId设置需要绘制元素的id,该元素就会以独立的item绘制显示出来。
处理过程如下:
1、 使用QSvgRenderer加载SVG文件
2、 创建空的QGraphicsSvgItem实例
3、 给QGraphicsSvgItem实例使用setSharedRenderer设置1中的QSvgRenderer为共享Renderer
4、 给QGraphicsSvgItem实例设置要绘制元素的id,则当前item只绘制该item
所有元素都单独绘制出来后,可以使用组合组合所有元素为一个完整的SVG,同时可以再次布局SVG中不同元素的位置。
2. 视图场景中SVG元素属性修改显示
SVG图形加载到视图场景中后,是通过QT Painter绘制图形到窗口,已经与SVG文件脱离了关系,窗口中的图形只能显示,无法再次编辑。只是显示SVG图形无法满足博主的需求,博主需要在视图场景中再次编辑SVG图形的某些样式,QT没有提供类似功能接口,只能自行实现。通过分析以上QT提供的几个SVG操作类,我们可以采用变通方式实现编辑SVG图形:修改SVG文件中xml内容,保存再次加载到视图场景中,实现视图场景中SVG图形变化,实现二次编辑功能效果。
具体实现方法如下:
1、 读取SVG文件到内存,并使用QGraphicsSvgItem加载展示SVG图形
2、 通过XML读写类编辑内存中SVG文件内容
3、 获取QGraphicsSvgItem的QSVGRenderer指针,QSVGRenderer重新加载渲染SVG文件即可
3. 视图场景中SVG图形的大小调整
在视图场景中通过拖拽实现SVG图形整体大小调整,由于SVG是矢量图形,这里的大小调整就是拉伸或者缩放SVG图形。通过交互式鼠标拖拽SVG图形实现水平或垂直拉伸,Qt视图场景框架本身并没有现成接口支持鼠标拉伸item功能,需要自行实现。这里我们自行实现了GraphicsItemResizer类,实现item选中虚线边框和可拖拽小矩形热点。针对SVG图形Item的拖拽我们子类SVGItemResizer实现,我们使用一种简单的方式,使用水平或垂直方向缩放功能实现拖拽效果,也就是说拖拽SVG图形Item实际上是在放大或缩小SVG图形,缩放比例记录在item的Transform中,可以方便获取。这种方式也即boundingRect大小不变,改变的是场景中sceneBoundingRect大小。
4. 视图场景中多个SVG图形合并生成新的SVG图形文件
在视图场景中改变SVG图形Item大小不止Transform缩放方法这一种,首先是因为它实现简单且可以实现拖拽大小效果。其次,更重要的一个原因是多SVG合并功能需要用到Transform。
在视图场景中编辑SVG图形最重要的一个功能场景就是导入的多个SVG图形重新布局位置,然后合并成为一个新的SVG图形画面,并保存成为一个SVG文件。实现该功能的思路是:提取单个SVG文件中svg标签中的xml内容,将内容放入g标签内作为新SVG文件中的一个子节点,然后按照SVG item层级由低到顶在新SVG文件中从前到后排列g标签,最后保存为一个SVG文件。
这里有几点说明:
1、 SVG图形是根据文件中元素顺序从前往后绘制的,即xml文件中排在前面的元素先绘制,处在底层,排在后面的元素后绘制,处在上层,SVG中本身没有设置元素层级的属性,是通过xml文件中元素顺序实现的,这一点与视图场景中的item不同,item本身有ZValue值可以设置,所以在合并多个SVG图形item时,先对item依据ZValue值有小到大排序,按顺序合并到新SVG文件中。
2、 视图场景中重新布局的SVG位置和大小等信息如何写入新SVG文件中?这里就用到了Transform,熟悉SVG的同学应该都知道SVG中元素布局用到的transform属性,同时视图场景中item的位置变换信息也是在QTransform中,SVG的transform属性和item的QTransform是对应的,这就完美解决了我们的问题。我们保存的新SVG是以Scene大小为SVG实际大小,这样item在Scene中布局信息与新SVG布局信息是对应的,这里SVG外包的g标签的transform属性就和item的sceneTransform完全对应,最后我们只需将sceneTransform转换为transform属性字符串写入新SVG文件中即可。
经测试验证该方法可以实现多SVG图形合并,已经应用到作者开发项目当中。
5. 开发中遇到的问题
1、最大的一个坑就是QtSvg本身支持的SVG版本低,如文章开头所诉,加载某些SVG图形会出现绘制问题,这个没办法,目前qt新版本依然没有升级该模块,有坑请绕行!
2、合并多个SVG图形文件时,需要避免不同SVG文件中元素id相同,相同的id可能会导致引用的样式发生冲突,进而导致合并后的SVG图形出现意料之外的显示效果。
3、合并操作SVG文件内容时,内容字符串编码格式一定要保证为UTF-8,否则中文会出现乱码,进而导致合并SVG时会出现各种奇怪的问题。字符串读写中间操作可以使用QTextStream设置编码再操作。
- Qt视图场景框架之SVG
- Qt视图场景框架之一些“坑”
- Qt视图场景框架之仿射变换
- Qt之图形视图框架
- Qt之图形视图框架
- Qt之图形视图框架
- Qt之图形视图框架
- QT 图形视图框架之角色移动
- qt之图形视图框架(上)
- qt之图形视图框架(下)
- QT视图框架
- QT图形视图框架
- QT图形视图框架
- Qt图形视图框架
- QT 图形视图框架
- QT图形视图框架
- Qt中的图形视图框架
- Qt之模型/视图
- 用qt和seetaface制作人脸识别程序的准备工作备忘
- Linux编程预习
- Jhipster初识
- Makefile自动产生依赖
- Google Guava 使用经验总结
- Qt视图场景框架之SVG
- win下安装spring boot cli
- [arc082e]ConvexScore
- 消息队列-ActiveMQ学习笔记(二)-点对点消息实现
- mysql安装全过程
- 零基础学图形学(5) 几何知识——矩阵
- 使用正则表达式进行匹配
- 图片生成beta64
- C++中的命名空间、using用法、区域运算符(::)详解