Qt自学之路(六)-自制Json文件编辑查看工具

        经过之前的学习,对Qt框架有了一些基本理解。正好工作中需要对Json文件进行查看和编辑,所以决定用Qt框架制作一个Json文件查看编辑工具。

1、软件功能介绍

        介绍软件功能之前,先给大家看一下软件的截图:

        

 软件支持的主要功能如下:

(1)以层级形式显示json文件内容。每个节点的key用红色文字表示,value用绿色文字表示。当前节点用黄色文字显示。

(2)父节点key值后面括号中的内容表示了父节点的类型(是一个对象,还是一个数组)

(3)被选中的节点,会以key(...):value(...)样式进行显示。

(4)双击选中节点的key或value字段,会弹出编辑控件供用户输入新值。

(5)点击父节点左侧的按钮可以对父节点进行展开或折叠操作。

(6)敲击键盘的上下键可以遍历数据节点。

(7) 点击del键或者在编辑菜单栏中点击删除按钮,会删除当前选中节点。

(8)在编辑菜单栏中点击插入按钮,会对当前选中节点追加子节点。

2、本软件所涉及的Qt知识如下:   

(1)信号与槽机制

(2)layout机制:自制layout mananger

(3)model/view框架:自制model类,自制view类

(4)事件机制:重写事件处理虚函数

(5)Qmake:编写项目文件

3、项目组成   

 (1)本程序由两个模块组成:

        1)JsonModel模块:主要实现自制model类相关功能。

        2)JsonViewer主模块:主要实现自制view类相关功能,主窗口功能,展开折叠按钮功能等。

(2)JsonModel模块类型为静态库,项目文件如下:

 其中值得说明的是图中标红框的内容。TEMPLATE变量赋值为lib,表示这个项目是一个库项目,CONFIG变量追加staticlib字符串说明这个库是一个静态库。

(3)JsonViewer模块类型为app,项目文件如下:

值得说明的内容是图中标红框的内容,LIBS变量追加JsonModel.lib文件的相对路径,表示本模块需要连接JsonModel库文件。

4、JsonModel类实现

(1)首先给大家展示一下jsonModel的定义:

(2)json文件解析后获取的数据的组织结构实际上是一个树形结构。因此在JsonModel类中,也是用一个多叉树来对底层数据进行存储。在JsonModel类中通过m_rootP成员变量指向树的根节点。

 (3)TreeItem类是自定义树节点类。它的定义如下:

TreeItem类中m_childs是一个子节点的列表。m_value成员变量记录的是Json节点的value值,key记录了Json节点的key值。

(4)在JsonModel构造函数中会调用_setupModelData()成员函数对Json字符串进行解析,并创建底层多叉树。

(5)JsonModel提供的数据抽象组织形式如下图所示:

每个子表格都有两列,第一列对应于key值,第二列对应于value值。

(6)重写index()虚函数

index()函数实现如下:

每个index对象的内部数据指针(internalPointer)指向对应的底层树节点对象。

data()函数实现如下:

 通过index的内部数据指针可以获取对应的底层树节点。如果column为0则返回树节点的key值,为1则返回树节点的value值。

rowCount()函数实现如下:

通过parent索引的内部数据指针可以获取对应的底层树节点。树节点的包含的子节点数即为子表格的行数。

columnCount()函数实现如下:

因为model每个子表格都固定包含两列,所以此函数返回值为2;

 setData()函数如下:

通过index获取对应的底层树节点,如果column值为0则修改key值,如果column值为1则修改value值。并发送dataChanged信号。

insertRows()函数如下:

通过index获取对应的底层树节点,创建一个新的子节点,并将它追加到树节点的子节点列表中。

flags()函数实现如下:

通过这个函数可以控制哪些数据项是可编辑的。在本程序中,次顶级表格中的数据项是不能编辑的。这个表格中的数据项对应于底层树结构的根节点。

 5、JsonView类实现

(1)先展示一下JsonView类的定义

 (2)initial()函数实现如下:

在初始化函数中,对滚动条进行了初始化。设置了view显示的model对象。设置了view的选择模式仅支持单选。将model的rowsRemoved信号连接到了view的rowsRemoved槽中。读取了模型中的数据。

(3)readModel()函数实现如下:

 

在readModel()函数中会调用_readModel()函数,_readModel()函数是一个递归函数,它读取index对应的数据并生成布局对象。

(4)_createJsonLayout()函数实现如下:

一个布局对象包含:一个key对象,一个value对象,一个展开/折叠按钮,以及一个子布局列表。

(5)indexAt()函数实现如下:

 

这个虚函数判断鼠标坐标是否在某个key对象或者value对象范围内。如果处于某个对象范围内,则返回这个对象对应的index。_forEachItem()函数会遍历model中的所有数据项。check函数可以起到剪枝作用,在对子节点进行遍历前,先判断globlePoint是否在子布局范围内,如果在范围内才对子布局进行遍历。

(6)dataChanged函数实现如下:

 

当双击某个节点的key对象或者value对象,view会调用默认delegate对象弹出编辑控件,当用户输入完成后,view对象会调用delegate的接口函数对model进行修改。model数据修改后会发送dataChanged信号。view的dataChanged槽就会被调用。

在dataChanged()槽函数内部,通过index调用_getLayout()函数可以获取index对应的layout对象,之后根据index的column值为0或者为1,对key对象或者value对象进行修改。

(7)rowInserted()函数实现如下:

当model某个子表格中插入了一行数据,则view的insertRows()槽会被调用。rowInserted()函数获取parent index对应的layout对象,对layout对象添加新的子layout对象。之后调用_updateAll()函数对整体布局进行刷新。_updateChildItemsIndex()函数更新子布局内部的索引。

(8)rowsAboutToBeRemoved()函数及rowsRemoved()函数实现如下:

在rowsAboutToBeRemoved()函数中删除父layout对象的子布局。(需要在此函数中对layout对象进行修改,因为rowsAboutToBeRemoved()返回后在rowsRemoved()函数调用前,paintEvent()函数会被调用)。

rowsRemoved()函数中对子布局内对象的index进行更新。如果删除的是根数据项,则添加一个空的根数据项。

(8)paintEvent()函数的实现如下:

在paintEvent()函数中,先对view背景进行刷新,之后计算需要更新的layout对象列表,并对列表中的每个layout对象进行绘制。jsonView类没有通过delegate对象对数据项进行绘制,而是直接在paintEvent()函数中进行绘制。

6、JsonLayout类实现

(1)首先展示一下JsonLayout类的定义:

(2)采用JsonLayout类,主要是因为model底层数据为树形结构,而layout内涵的组合设计模式正好适合表示这样的层级结构。实践证明,采用这种方式确实可以使代码更加简洁,逻辑更加清晰。

(3)JsonLayout类主要包含两个职责:

        1)对数据项进行自动布局

        2)对数据项进行绘制

出于简洁考虑,绘制操作没有单独写一个类,而是含在了JsonLayout类中。

(4)setGeometry()函数实现如下:

在这个函数中,根据key对象,value对象,展开/折叠按钮对象,子layout对象的sizeHint计算各自的geometry。

(5)sizeHint()函数及reCalculateSizeHint()函数实现如下:

 

 

出于效率考虑,用m_sizeHint成员变量记录每次计算出的sizeHint值。sizeHint()函数直接返回m_sizeHint成员变量的值。reCalculateSizeHint(),reCalculateChildsSizeHint(),reCalculateParentsSizeHint()函数在数据修改时,或者展开/折叠按钮被按下时重新计算所有layout对象的sizeHint值。

7、JsonViewer类实现

(1)给大家展示一下JsonViewer类的定义:

JsonViewer类是程序的主窗口类。其中主要包含了菜单的实现。

(2)文件菜单的实现如下:

 (3)主窗口初始化操作实现如下:

在这个函数中,创建了model对象,并将view对象于model对象进行关联。将JsonViewer的dataChanged槽链接到model对象的dataChaged信号上。

JsonViewer的dataChanged槽函数主要记录了底层数据是否被修改过。如果底层文件被修改过,那么在文件关闭时提示用户保存。

(4)打开文件实现如下:

 (5)保存文件实现如下:

(6)关闭文件实现如下:

 

(7)插入和删除行操作如下:

 8、main函数实现如下:

 9、为了验证JsonView类可以显示任意model,修改main函数如下:

显示文件夹内容效果如下: 

 10、为了验证任何view类都可以显示JsonModel,main函数修改如下:

用QTreeView类显示效果如下: 

 11、小结

这个程序并不复杂,其中涵盖了一些之前所学的Qt知识。本程序其实也可以不使用layout机制,可以定义一个采用组合设计模式的类实现同样的功能。程序可能还有一些不完善需要改进的地方,也请各位大神多多指点。

        

        

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值