QT的Tree View Model示例

2023-11-09

一、介绍

使用MVC架构,Tree View与Tree Widget 相比而言,需要为tree view 设置一个model,使Tree View 能有效降低内存的使用率。下面参考Qt官方提供的demo——Simple Tree Model(说是简单的树试图模型Demo,其实一点都不简单)效果图如下:

二 、 自定义树模型结构TreeItem

使用TreeItem对象把数据存储在模型内部,这些对象以基于指针的树结构链接在一起。通常,每个TreeItem都有一个父项,也可以有许多子项。然而,树结构中的根项没有父项,而且它永远不会在模型之外被引用。每个TreeItem都包含它在树结构中的位置信息;它可以返回父项及其行号。有了这些信息就可以更容易地实现模型。

由于树视图中的每一项通常包含几列数据,因此很自然地将这些信息存储在每一项中。为了简单起见,我们将使用QVariant对象列表来存储项中每一列的数据。

在 tree model中顶级项(上图中的 A、C以及同级的Item)对应的模型索引的父索引(QModelIndex::parent()函数获得)是无效的。各项的数据保存在QModelIndex中。

数据结构如下:

treeitem.h

 
#include <QList>
#include <QVariant>
 
class TreeItem
{
public:
	TreeItem(const QList<QVariant> &data, TreeItem *parent = nullptr);
	~TreeItem();
 
	// 构建子Item列表;
	void appendChild(TreeItem *child);

	// 获取该Item指定行号的子Item;
	TreeItem *child(int row);

	// 获取该Item的子Item个数;
	int childCount() const;

	// 获取该Item的列数(数据段数); 
	int columnCount() const;

	// 获取该Item指定段的数据;
	QVariant data(int column) const;

	// 获取该item所在parent的row;
	int row() const;

	// 该Item的父Item;
	TreeItem *parentItem();
 
private:
	TreeItem* m_parentItem;				// 该Item的父Item;
	QList<TreeItem*> m_childItems;		// 该Item的子Item列表;
	QList<QVariant>	m_itemData;			// 该Item的各列数据;
};

 treeitem.cpp

#include "tree_item.h"
 
TreeItem::TreeItem(const QList<QVariant> &data, TreeItem *parent)
	:m_itemData(data), 
	m_parentItem(parent)
{
 
}
 
TreeItem::~TreeItem()
{
	qDeleteAll(m_childItems);
}
 
void TreeItem::appendChild(TreeItem *child)
{
	m_childItems.append(child);
}
 
TreeItem *TreeItem::child(int row)
{
	// 无效的row;
	if (row < 0 || row >= m_childItems.size())
		return nullptr;
 
	return m_childItems.at(row);
}
 
int TreeItem::childCount() const
{
	return m_childItems.count();
}
 
int TreeItem::columnCount() const
{
	return m_itemData.count();
}
 
QVariant TreeItem::data(int column) const
{
	// 无效的索引返回空的QVariant;
	if (column < 0 || column >= m_itemData.size())
		return QVariant();
 
	return m_itemData.at(column);
}
 
int TreeItem::row() const
{
	if (m_parentItem)
		m_parentItem->m_childItems.indexOf(const_cast<TreeItem*>(this));
 
	// 尽管根项(没有父项)被自动分配了行号0,但模型从不使用此信息。
	return 0;
}
 
TreeItem *TreeItem::parentItem()
{
	return m_parentItem;
}

三、自定义Model

一般用TreeModel都是用自己的类,于是,按着文档上说明的,关于继承QAbstractItemModel的时候,必须实现如下几个函数:index(), parent(), rowCount(), columnCount(), data(), 要让Model变成可以编辑的话,必须还要实现 setData(), flags() 这两个函数,让flags()返回值有ItemIsEditable。 同时,还可以实现headerData()和 setHeaderData() 来控制View中的标题。需要重写父类的函数(override标记)每个函数有较详细的解释。

treemodel.h

#ifndef TREEMODEL_H
#define TREEMODEL_H

#include <QAbstractItemModel>
#include <QModelIndex>
#include <QVariant>

class TreeItem;

//! [0]
class TreeModel : public QAbstractItemModel
{
    Q_OBJECT

public:
    explicit TreeModel(const QString &data, QObject *parent = 0);
    ~TreeModel();

    QVariant data(const QModelIndex &index, int role) const override;
    Qt::ItemFlags flags(const QModelIndex &index) const override;
    QVariant headerData(int section, Qt::Orientation orientation,
                        int role = Qt::DisplayRole) const override;
    QModelIndex index(int row, int column,
                      const QModelIndex &parent = QModelIndex()) const override;
    QModelIndex parent(const QModelIndex &index) const override;
    int rowCount(const QModelIndex &parent = QModelIndex()) const override;
    int columnCount(const QModelIndex &parent = QModelIndex()) const override;

private:
    void setupModelData(const QStringList &lines, TreeItem *parent);

    TreeItem *rootItem;
};
//! [0]

#endif // TREEMODEL_H

treemodel.cpp

#include "treeitem.h"
#include "treemodel.h"

#include <QStringList>

//! [0]
TreeModel::TreeModel(const QString &data, QObject *parent)
    : QAbstractItemModel(parent)
{
    QList<QVariant> rootData;
    rootData << "Title" << "Summary"; // set header
    rootItem = new TreeItem(rootData);
    setupModelData(data.split(QString("\n")), rootItem);
}
//! [0]

//! [1]
TreeModel::~TreeModel()
{
    delete rootItem;
}
//! [1]

//! [2]
int TreeModel::columnCount(const QModelIndex &parent) const
{
    if (parent.isValid())
        return static_cast<TreeItem*>(parent.internalPointer())->columnCount();
    else
        return rootItem->columnCount();
}
//! [2]

//! [3]
QVariant TreeModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid())
        return QVariant();

    if (role != Qt::DisplayRole)
        return QVariant();

    TreeItem *item = static_cast<TreeItem*>(index.internalPointer());

    return item->data(index.column());
}
//! [3]

//! [4]
Qt::ItemFlags TreeModel::flags(const QModelIndex &index) const
{
    if (!index.isValid())
        return 0;

    return QAbstractItemModel::flags(index);
}
//! [4]

//! [5]
QVariant TreeModel::headerData(int section, Qt::Orientation orientation,
    int role) const
{
    if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
        return rootItem->data(section);

    return QVariant();
}
//! [5]

//! [6]
QModelIndex TreeModel::index(int row, int column, const QModelIndex &parent)
const
{
    if (!hasIndex(row, column, parent))
        return QModelIndex();

    TreeItem *parentItem;

    if (!parent.isValid())
        parentItem = rootItem;
    else
        parentItem = static_cast<TreeItem*>(parent.internalPointer());

    TreeItem *childItem = parentItem->child(row);
    if (childItem)
        return createIndex(row, column, childItem);
    else
        return QModelIndex();
}
//! [6]

//! [7]
QModelIndex TreeModel::parent(const QModelIndex &index) const
{
    if (!index.isValid())
        return QModelIndex();

    TreeItem *childItem = static_cast<TreeItem*>(index.internalPointer());
    TreeItem *parentItem = childItem->parentItem();

    if (parentItem == rootItem)
        return QModelIndex();

    return createIndex(parentItem->row(), 0, parentItem);
}
//! [7]

//! [8]
int TreeModel::rowCount(const QModelIndex &parent) const
{
    TreeItem *parentItem;
    if (parent.column() > 0)
        return 0;

    if (!parent.isValid())
        parentItem = rootItem;
    else
        parentItem = static_cast<TreeItem*>(parent.internalPointer());

    return parentItem->childCount();
}
//! [8]

// 参数1: txt文件所有行的数据,参数2:TreeItem的父节点
void TreeModel::setupModelData(const QStringList &lines, TreeItem *parent)
{
    QList<TreeItem*> parents;
    QList<int> indentations;
    parents << parent;
    indentations << 0;

    int number = 0;

    while (number < lines.count()) {
        int position = 0;
        // 获取此行中第一个不是' '的位置
        while (position < lines[number].length()) {
            if (lines[number].at(position) != ' ') {
                break;
            }
            position++;
        }
        // 获取此位置之后的所有字符串,然后去除字符串前面和后面的的空格
        QString lineData = lines[number].mid(position).trimmed();

        if (!lineData.isEmpty()) {
             //使用“\t”划分字符串为字符串列表.
            QStringList columnStrings = lineData.split("\t", QString::SkipEmptyParts);
            QList<QVariant> columnData; // 列数据
            for (int column = 0; column < columnStrings.count(); ++column)
                columnData << columnStrings[column];

            // 根据缩进来判断是成为当前分支的兄弟,还是当前分支的儿子
            if (position > indentations.last()) {
                // The last child of the current parent is now the new parent
                // unless the current parent has no children.
                //当成为前分支的儿子
                if (parents.last()->childCount() > 0) {
                    parents << parents.last()->child(parents.last()->childCount() - 1);
                    indentations << position;
                }
            }
            else {
                while (position < indentations.last() && parents.count() > 0) {
                    parents.pop_back();
                    indentations.pop_back();
                }
            }

            // Append a new item to the current parent's list of children.
            parents.last()->appendChild(new TreeItem(columnData, parents.last()));
        }

        ++number;
    }
}

 四、程序的入口

资源文件

main函数

#include <QApplication>
#include <QFile>
#include <QTreeView>

int main(int argc, char *argv[])
{
    Q_INIT_RESOURCE(simpletreemodel);

    QApplication app(argc, argv);

    QFile file(":/default.txt");
    file.open(QIODevice::ReadOnly);
    TreeModel model(file.readAll());
    file.close();

    // 创建以View显示model
    QTreeView view;
    view.setModel(&model);
    view.setWindowTitle(QObject::tr("Simple Tree Model"));
    view.show();
    return app.exec();
}

参考:

Qt官方demo日拱一卒- simple tree model_feima9999的博客-CSDN博客

Qt —— 细说自定义Tree View Model_ypy9323的博客-CSDN博客

QT Tree model_zhu_nn的博客-CSDN博客

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

QT的Tree View Model示例 的相关文章

  • 如何在Qt3D中优化点云渲染

    我正在尝试使用 Qt3D 显示大型点云 20M pts 我第一次发现这个图书馆https github com MASKOR Qt3DPointcloudRenderer https github com MASKOR Qt3DPointc
  • 在 Windows 上从源代码构建 PhantomJS-2

    我正在尝试基于这些在 Windows 8 1 x64 上从源代码构建 PhantomJS 2 的开发版本指示 https github com ariya phantomjs wiki PhantomJS 2 但是我收到以下错误 mingw
  • Qt 和 MOC 的困境与简单的制作

    我想这更像是一个 GNU Make 问题 而不是 Qt 和 moc 但这里是 我有一个包含多个目录Q OBJECTS 我有一些简单的代码 它收集所有这些 例如 MOCS shell grep l Q OBJECT HEADERS Assum
  • 如何通过信号和槽传递参数?

    我的 GUI 包括LineEdit and a 按钮 当 的时候按钮单击后 插槽clicked 叫做 我想在之间建立信号槽关系clicked 作为信号和doSomething 作为插槽 问题是doSomething 无权访问 UI 并且do
  • Qt - QProcess 不工作

    我尝试启动 Internet Explorer 所以我使用下面的代码 QProcess process new QProcess this QString temp C Program Files Internet Explorer iex
  • 更改 Qt 中的语言环境

    我尝试使用 QLocale 和 setDefault 函数更改区域设置 但似乎不起作用 以下是使用 C 本地化库和 QLocale 更改语言环境的示例 对于 C 本地化库 它似乎可以工作 但对于 QLocale setDefault 函数调
  • Qt 码头调整大小事件

    有没有办法在 Qt 中捕捉码头的调整大小事件 我需要能够检测到扩展坞何时调整大小 而不仅仅是其位置或 功能 发生变化时 看起来 QDockWidget 没有 调整大小 信号 如果您不希望子类化以仅获得调整大小事件控件 您可以安装事件过滤器
  • Qt QML MenuItem iconSource不显示

    我有一个非常简单的设置只是为了说明问题 import QtQuick Controls 1 4 import QtQuick Window 2 2 ApplicationWindow visible true width 640 heigh
  • 将 QMAKE_CXXFLAGS += -std=c++11 添加到 qt 中的 .pro 文件不起作用(在 linux 12.04 上)

    编译器输出 main o 错误 1 cc1plus 错误 无法识别的命令行选项 std c 11 解决方案是更新系统上的旧 gcc 版本 事实上 我很惊讶你的 12 04 Ubuntu 变体上有这么旧的版本 默认情况下应该有 4 6 3 您
  • 错误:命名空间“std”中没有名为“enable_if_t”的模板;您的意思是“enable_if”吗?

    我正在 macOS 10 13 6 上使用 Qt 5 11 3 进行编译 Qt使用的clang版本是 Applications Xcode app Contents Developer Toolchains XcodeDefault xct
  • QStandardItemModel::removeRows() 在我的用例中不起作用

    基本上我想删除模型中的所有行 我更喜欢使用removeRows 代替clear 因为我想保留我的标题 我想我错过了一些东西 文档在这里 http doc qt nokia com 4 7 snapshot qstandarditemmode
  • QTableView 选择已更改

    我有一个QTableView我需要从中获取选择更改事件 我似乎无法让连接工作 我有 MyWidget h protected slots void slotLoadTransaction const QItemSelection selec
  • C++:头文件中全局函数的多重定义错误

    该函数是全局的 在头文件中定义 暂时地我想把它留在那里 头文件还构成一个具有内联函数的特定类 其中一个函数调用this全局函数 源文件不包含任何有问题的全局函数 有关错误原因的任何提示吗 如果有人感兴趣的话我可以发布代码 mainwindo
  • 如何搭建qtwayland?

    我花了一整天的时间尝试使用QtWayland Compositor 1 0在 Qt 创建者中 我已经遵循了从那里开始的所有步骤https wiki qt io QtWayland https wiki qt io QtWayland但我收到
  • 使用 QSet 作为 Qt 地图容器中的键

    我需要一个映射 其中键是唯一的 并且每个键都是一组或自定义 POD 结构 其中包含 3 个数据项 这些值只是指向对象实例的指针 从阅读Qt 的 QMap 与 QHash 的文档 http qt project org doc qt 4 8
  • 在 4K 屏幕上使用 Matplotlib 和 TKAgg 或 Qt5Agg 后端

    我在 Ubuntu 16 04 上使用 Matplotlib 2 0 和 Python 3 6 来创建数据图 电脑显示器的分辨率为 4k 分辨率为 3840x2160 绘图数字看起来非常小 字体也很小 我已经尝试过TKAgg and Qt5
  • 带 Qt 的菜单栏/系统托盘应用程序

    我是 Qt PyQt 的新手 我正在尝试制作一个应用程序 其功能将从菜单栏 系统托盘执行 这里展示了一个完美的例子 我找不到关于如何做到这一点的好资源 有人可以建议吗 Thanks 我认为您正在寻找与QMenu and QMainWindo
  • Qt 5.5 QOpenGLWidget 链接错误未链接任何 openGL 调用

    我尝试使用 Qt 5 5 1 构建一个简单的 OpenGL 应用程序 一切都很好 直到我尝试使用 glClearColor 等 openGL 本机函数调用 该小部件实际上编译并产生黑屏 但在我尝试使用任何 openGL 本机函数后 它甚至不
  • 另一个宏中的 Q_PROPERTY 宏

    如何放置Q PROPERTY另一个宏里面 辅助宏 define SimpleAllinOne member type public void Set member type arg member m member arg member ty
  • 我应该使用 QCoreApplication::processEvents() 还是 QApplication::processEvents()?

    我有一个从两者调用的方法QThreads和主线程 这个方法有时可能需要很长时间才能在循环中进行计算 所以我把QCoreApplication processEvents 这可以防止 GUI 冻结 在某个时刻我已经改变了QCoreApplic

随机推荐

  • yaml for java_java操作yaml文件

    前言 YAML YAML Ain t Markup Language 也可以叫做YML 是一种人性化的数据序列化的语言 类似于XML JSON SpringBoot的配置文件就支持yaml文件 官网 语法 大小写敏感 使用缩进表示层级关系
  • 快速上手笔记,PyTorch模型训练实用教程(附代码)

    前言 自 2017 年 1 月 PyTorch 推出以来 其热度持续上升 一度有赶超 TensorFlow 的趋势 PyTorch 能在短时间内被众多研究人员和工程师接受并推崇是因为其有着
  • JAVA程序员预备知识&初识JAVA

    JAVA程序员预备知识 什么是计算机 能够按照程序运行 自动 高速处理海量数据的现代化智能电子设备 由硬件和软件组成 广泛应用在 科学计算 数据处理 自动控制 人工智能等 计算机硬件 一些物理装置按系统结构的要求构成一个有机整体 组成 CP
  • Linux 快捷键

    Linux 快捷键 文章目录 linux控制台快捷键 linux控制台快捷键 ctrl a e Ctrl Shift n 新终端 Shift Ctrl T 打开新的标签页 Shift Ctrl W 关闭标签页 Alt 数字 切换至对应的标签
  • Hive--HiveQL:查询

    4 查询 4 1 select from语句 4 1 1 基本操作 select是SQL的射影算子 from子句标识了从哪个表 视图或嵌套查询中选择记录 回顾之前创建的employees表 hive mydb gt create table
  • 【Detectron2】入门05 Schedules Faster R-CNN

    Detectron2的Learning Rate和Schedules 1x and 3x schedules 1x 16 images iterations 90 000 iterations in total with the LR re
  • 14 - Spring5 学习笔记 - 整合日志框架、@Nullable 注解

    Spirng5 框架新功能 1 整个 Spring5 框架基于 Java8 运行时兼容 JDK9 许多不建议使用的类和方法在代码库中删除 2 Spring5 框架自带了通用的日志封装 1 Spring5 已经移除了 Log4jConfigL
  • c++ 不插入重复元素但也不排序_十大经典排序算法,看这篇文章就够了

    微信公众号 小超说 如果你觉得对你有帮助 欢迎分享 如果你想系统地学习 建议在电脑端阅读 我想大家学习算法之旅的开端就是各种排序算法吧 的确 排序算法广泛的应用性以及它的简洁基础等性质是初学者的不二之选 那今天我就带着你复习回顾以下各种经典
  • Docker镜像相关操作有哪些?

    什么是Docker Docker是一个开源的应用容器引擎 它让开发者可以打包他们的应用以及依赖包到一个可移植的容器中 然后发布到安装了任何 Linux 发行版本的机器上 Docker基于LXC来实现类似VM的功能 可以在更有限的硬件资源上提
  • 2020年第十一届蓝桥杯省赛javab组寻找2020

    简单的模拟 向右 向下 向右下 package 算法 import java util Scanner public class 寻找20 static int N 100000 4 5 static int M 1000 5 static
  • python实现车牌识别系统

    车牌识别系统 算法参考 http www zengqiang club blog 34 GUI参考 https blog csdn net wzh191920 article details 79589506 基于opencv的模板识别来实
  • 设计模式的应用场景(9)--装饰模式

    装饰模式 定义 装饰模式以对客户端透明的方式扩展对象的功能 是继承方案的一个替代方案 提供比继承更多的灵活性 优点 能够提供比使用继承关系更加灵活的拓展对象的功能 它可以动态增加对象的功能并且可以随意组合这些功能 缺点 使用装饰模式进行设计
  • Hadoop学习之Hadoop完全分布式集群安装

    注 本文的主要目的是为了记录自己的学习过程 也方便与大家做交流 转载请注明来自 http blog csdn net ab198604 article details 8250461 要想深入的学习hadoop数据分析技术 首要的任务是必须
  • 在 Python 中生成随机字符串

    介绍生成随机字符串的几种方法 1 使用random choice 实现 import string import random number of strings 5 length of string 8 for x in range nu
  • Latex的使用

    1 语法规则 是TeX中做为命令的标志 格式 命令名 可选参数 不可省略参数 2 常用的宏包 amsmath 数学符号与公式宏包 amsfonts 数学符号与字体宏包 Ctex 支持中文的排版 gaphicx 插图处理 Xcolor 颜色处
  • Vmwarexiade镜像下载地址

    https msdn itellyou cn 复制链接在迅雷上下载
  • Reactive判断的API,toRef & toRefs,ref其他的API,customRef

    Reactive判断的API isProxy 检查对象是否是由 reactive 或 readonly创建的 proxy isReactive 检查对象是否是由 reactive创建的响应式代理 如果该代理是 readonly 建的 但包裹
  • 基于Arduino Uno的智能小车(可遥控,避障,调速)模块:L298N HC-05 HC-SR04及sg90(180度)舵机

    文章目录 一 先让小车动起来 二 加入对应模块实现对应功能 1 HC SR04及SG90舵机 2 完整程序编写 总结 一 先让小车动起来 1 用到的函数 定义引脚的输入 输出函数 pinMode pin OUT INPUT 通过使用pinM
  • jupyter 设置主题Error:Could not find a version that satisfies the requirement jupyterthemes from version

    1 jupyter设置主题的步骤 命令窗口输入 pip install jupyterthemes 具体主题讲解可参考 https www cnblogs com shanger p 12006161 html 2 遇到的问题 Could
  • QT的Tree View Model示例

    一 介绍 使用MVC架构 Tree View与Tree Widget 相比而言 需要为tree view 设置一个model 使Tree View 能有效降低内存的使用率 下面参考Qt官方提供的demo Simple Tree Model