QT学习笔记(15)-读取XML文件显示为树形结构

前言

像题目所说,本篇博客完成的需求为读取xml文件,并将其显示为树形结构。这里理所当然,运用的知识应为mvc模式+QTreeView+QStandardItemModel这三大块,接下来,我将逐渐讲述着三大块的知识。

知识点详解

MVC模式

其实Qt中的MVC并不叫MVC,而是叫“MVD”,Qt中没有Controller的说法,而是使用了另外一种抽象: Delegate (委托) ,其行为和传统的MVC是相同的。写过C#的同学肯定对delegate就不陌生了,这里delegate的用法就是负责协调Model和View之间的数据。其思想如下图所示:
在这里插入图片描述
Model是唯一和数据集打交道的组件,View不接触数据源,其所需要的数据可以从Model中取出,而Delegate正式负责协调Model和View上数据。这种将view和数据源隔离的方式有几点好处:
1、在处理较大的数据集时每个组件各司其职,不至于降低性能。
2、一个Model可以映射到多个View,这样可以以不同的方式查看数据同一份数据。
3、如果底层数据源的存储改变了,我们只需要处理Model就可以了。
举个具体的例子:
在这里插入图片描述
上面的知识讲解,相信你应该已经能够理解MVD的大约模式了。而QT的MVD模式有很多其独具一格的特性,下面就是一些常见的使用类。
模型model(表示数据)
抽象基类QAbstractItemModel
列表的抽象基类QAbstractListModel、表格的抽象基类QAbstractTableModel
QDirModel类是文件与目录的存储模型
QStandardItemModel类
QStringListModel类
视图view(表示用户界面)
抽象基类QAbstractItemView
QListView—QListWidget\QUndoView
QTableView—QTableWidget
QTreeView—QTreeWidget
QColumnView
QHeaderView
实际上:QListWidget、QTableWidget、QTreeWidget已经包含数据,是模型与视图集成的类
代理delegate(自定义数据条目item的显示与编辑方式)
抽象基类QAbstractItemDelegate
QItemDelegate/QStyleItemDelegate
类QItemDelegate 由类QSqlRelationDelegate继承

在完成前言所言的上述需求中,我们只需要用到MV两种方式,第三种,大家可以看一下我的这篇博文QT学习笔记(8)-QDomDocument解析以及QTableView显示

QStandardItemModel

QStandardItemModel 是标准的以项数据(item data)为基础的标准数据模型类,通常与 QTableView 组合成 Model/View 结构,实现通用的二维数据的管理功能。
QStandardltemModel 的使用,主要用到以下 3 个类:

  1. QStandardItemModel:基于项数据的标准数据模型,可以处理二维数据。维护一个二维的项数据数组,每个项是一个 QStandardltem 类的变量,用于存储项的数据、字体格式、对齐方式等。
  2. QTableView:二维数据表视图组件,有多个行和多个列,每个基本显示单元是一个单元格,通过 setModel() 函数设置一个 QStandardItemModel 类的数据模型之后,一个单元格显示 QStandardItemModel 数据模型中的一个项。
  3. QItemSelectionModel:一个用于跟踪视图组件的单元格选择状态的类,当在 QTableView 选择某个单元格,或多个单元格时,通过 QItemSelectionModel 可以获得选中的单元格的模型索引,为单元格的选择操作提供方便。

然后,为了完成需求,你所要了解的是这篇博客使用QStandardItemModel创建子节点,如何使用这个类来创建子节点,这篇博客也是我的主要参考博客。

QTreeView

QTreeView是一个视图类,你需要手动给其指定模型类,才能够显示数据。此时,你便需要将其与QStandardItemModel类进行结合。关于这个知识点,我主要参考为博客为Qt中三种解析xml的方式,这三种解析方式,当然,我选择的是第二种,关于这三种的利弊,在文章中都有较好的讲解,值得一看。

程序详解

效果图

在这里插入图片描述
不管xml文件中有多少个节点,都可以以树形的方式进行展示。

代码

ServerTreeView.cpp

首先,你在View中,需先把要读取文件的路径传入类中,然后,调用模型的解析函数。

#include "ServerTreeView.h"
#include "ServerTreeModel.h"
CServerTreeView::CServerTreeView(QWidget *parent) : QTreeView(parent)
{
    p_saveProject = new CServerSaveProject();
    //在更改参数时,建议将复制过来的文件路径的斜杠更换一下方向,才能更好的识别
    QString fileName="E:/Test/test.xml";//这是要写入的目标文件。
    QString path = "E:/QT_Code/work_content/Day01";//这是要进行检测的目标文件夹
    p_saveProject->saveProject(fileName,path);
    initTreeView();
}
CServerTreeView::~CServerTreeView()
{
}
void CServerTreeView::initTreeView()
{
    QString xmlPath = "E:/Test/test.xml";
    p_model = new CServerTreeModel();
   // p_model->readByte(byteArray);
    this->setModel(p_model);//public void setModel(TreeModel newModel):根据传递的参数设置TreeModel的值
    //p_model->parseFile(xmlPath);//解析xml文件
    p_model->readFile(xmlPath);
    p_model->setHorizontalHeaderLabels(QStringList()<<QStringLiteral("文件名"));
    //this->setUpdatesEnabled(true);  //恢复界面刷新
}
void CServerTreeView::receiveByte(QByteArray byteArray)
{
    qDebug()<<"receiveByte";
    p_model->readByte(byteArray);
}

ServerTreeModel.cpp

主要的函数都已在下面进行展示了,首先,读取文件信息,setcontent于doc之中。然后,递归调用处理节点的函数,不断的把子节点链接在父节点上面ParentItem->appendRows(childItems);,从而实现不管xml文件有多少层,都可以实现展示。

#include "ServerTreeModel.h"

CServerTreeModel::CServerTreeModel(QObject *parent) : QStandardItemModel(parent)
{

}
CServerTreeModel::~CServerTreeModel()
{

}
bool CServerTreeModel::readFile(const QString &fileName)
{
    QFile file(fileName);
    if (!file.open(QFile::ReadOnly | QFile::Text)) {
        std::cerr << "Error: Cannot read file " << qPrintable(fileName)
                  << ": " << qPrintable(file.errorString())
                  << std::endl;
        return false;
    }

    QString errorStr;
    int errorLine;
    int errorColumn;

    QDomDocument doc;
    if (!doc.setContent(&file, false, &errorStr, &errorLine, &errorColumn))
    {
        std::cerr << "Error: Parse error at line " << errorLine << ", "
                  << "column " << errorColumn << ": "
                  << qPrintable(errorStr) << std::endl;
        return false;
    }

    QDomElement root = doc.documentElement();
    if (root.tagName() != "root")
    {
        std::cerr << "Error: Not a school file" << std::endl;
        return false;
    }
    else{

        QFileInfo appInfo(root.attribute("Path"));
        QString value = appInfo.baseName();//文件名
        item1 = new QStandardItem((value));
        this->appendRow(item1);
        qDebug()<<"root";
    }
    parseAllMembers(root,item1);
    //parseRootMembers(root);
    return true;
}
void CServerTreeModel::parseAllMembers(const QDomElement &element,QStandardItem *ParentItem)
{
    QDomNode child = element.firstChild();
    while(!child.isNull())
    {

        QFileInfo appInfo(child.toElement().attribute("Path"));
        QString value = appInfo.baseName();//文件名
        QString suffix = appInfo.suffix();
        QString readvalue = value + "."+suffix;
        ChildItem = new QStandardItem(readvalue);
        childItems.clear();
        childItems.push_back(ChildItem);
        ParentItem->appendRows(childItems);
        childItems.clear();
        if (child.toElement().tagName() == "Folder")
        {

            parseAllMembers(child.toElement(),ChildItem);
        }
        child = child.nextSibling();
    }

}

注意:这里的代码还依然使用了绝对路径,记得更改,但在后面的代码已经有对这点进行了修改了。这里就不修改了。需要更改后的,可以看第(16)篇文章,那个就都是使用了相对地址了。

代码地址

https://download.csdn.net/download/weixin_38809485/12624914中的MyTcpFile5

参考文献

  1. Qt QStandardItemModel用法(超级详细)
  2. Qt5MVC模式(一)
  3. Qt中的MVC (模型/视图结构)
  • 5
    点赞
  • 58
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值