基于Qt的Model-View显示树形数据

news2025/4/27 14:47:29

目标

用qt的模型-视图框架实现树型层次节点的显示,从QAbstractItemModel派生自己的模型类MyTreeItemModel,用boost::property_tree::ptree操作树型数据结构,为了演示,此处只实现了个只读的模型

在这里插入图片描述

MyTreeItemModel的定义

#pragma once

#include <QAbstractItemModel>
#include "boost/property_tree/ptree.hpp"

class MyTreeItemModel : public QAbstractItemModel
{
	Q_OBJECT

public:
	MyTreeItemModel(QObject *parent = 0);
	~MyTreeItemModel();

	virtual QModelIndex index(int row, int column,
		const QModelIndex &parent = QModelIndex()) const override;
	virtual QModelIndex parent(const QModelIndex &child) const override;
	virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override;
	virtual int columnCount(const QModelIndex &parent = QModelIndex()) const override;
	virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
	virtual Qt::ItemFlags flags(const QModelIndex &index) const override;
private:
	const boost::property_tree::ptree* GetParent(const boost::property_tree::ptree* pChild,
		int& nParentRow ) const;

private:
	// 创建一个property_tree
	boost::property_tree::ptree m_TreeItem;
};

MyTreeItemModel的实现

  1. 简化代码,直接在构造函数创建出树型数据结构,用的是boost库的property_tree::ptree

    MyTreeItemModel::MyTreeItemModel(QObject *parent)
    	: QAbstractItemModel(parent)
    {
    	// 添加数据
    	m_TreeItem.put("node", "root value");
    	m_TreeItem.put("node.child1", "child1 value1");
    	m_TreeItem.put("node.child2", "child2 value2");
    	m_TreeItem.put("node.child3", "child3 value3");
    
    	// 添加子节点
    	boost::property_tree::ptree child;
    	child.put("grandchild", "grandchild value4");
    	m_TreeItem.add_child("node.child4", child);
    	m_TreeItem.put("node.child4", "child4 value4");
    }
    
  2. 模型类必须实现index虚函数,视图、委托会调用index函数来访问模型数据,具体参看qt帮助文档

    QModelIndex MyTreeItemModel::index(int row, int column,
    	const QModelIndex &parent /*= QModelIndex()*/) const
    {
    	if (!hasIndex(row, column, parent))
    	{
    		return QModelIndex();
    	}
    
    	const boost::property_tree::ptree* pParent = nullptr;
    	if (!parent.isValid())
    	{
    		pParent = &m_TreeItem;
    	}
    	else
    	{
    		pParent = reinterpret_cast<boost::property_tree::ptree*>( parent.internalPointer() );
    	}
    
    	auto it = pParent->begin();
    	it = std::next(it, row);
    	const boost::property_tree::ptree* pThisItem = &(it->second);
    	if (pThisItem)
    	{
    		return createIndex(row, column, (void*)pThisItem);
    	}
    
    	return QModelIndex();
    }
    
  3. 模型类必须实现parent虚函数

    QModelIndex MyTreeItemModel::parent(const QModelIndex &child) const
    {
    	if (!child.isValid())
    		return QModelIndex();
    
    	boost::property_tree::ptree *childItem = static_cast<boost::property_tree::ptree*>(child.internalPointer());
    	
    	int nParentRow = 0;
    	const boost::property_tree::ptree* pParentItem = GetParent(childItem, nParentRow);
    	if (!pParentItem)
    	{
    		Q_ASSERT(false);
    		return QModelIndex();
    	}
    
    	if (pParentItem == &m_TreeItem)
    		return QModelIndex();
    
    	return createIndex(nParentRow, 0, (void *)pParentItem);
    }
    
  4. 模型类必须实现rowCount虚函数

    int MyTreeItemModel::rowCount(const QModelIndex &parent /*= QModelIndex()*/) const
    {
    	if (parent.column() > 0) //第一列才有子节点
    		return 0;
    
    	const boost::property_tree::ptree* pParent = nullptr;
    	if (!parent.isValid())
    		pParent = &m_TreeItem;
    	else
    		pParent = static_cast<const boost::property_tree::ptree*>(parent.internalPointer());
    
    	return pParent->size();
    }
    
  5. 模型类必须实现columnCount虚函数

    int MyTreeItemModel::columnCount(const QModelIndex &parent /*= QModelIndex()*/) const
    {
    	return 1; //只支持一列
    }
    
  6. 模型类必须实现data虚函数,因为是只读,只实现了Qt::DisplayRole

    QVariant MyTreeItemModel::data(const QModelIndex &index, int role /*= Qt::DisplayRole*/) const
    {
    	if (!index.isValid())
    		return QVariant();
    
    	if (role != Qt::DisplayRole)
    		return QVariant();
    
    	auto pTreeItem = static_cast<const boost::property_tree::ptree*>(index.internalPointer());
    	if (!pTreeItem)
    	{
    		Q_ASSERT(false);
    		return QVariant();
    	}
    
    	QString strValue = QString::fromStdString(pTreeItem->data());
    	return QVariant(strValue);
    }
    
  7. 重写flags函数,告诉使用者,本模型只提供只读功能,这里基类QAbstractItemModel的实现正好符合需求,可不重写,我这里写出来只是说明下而已

    Qt::ItemFlags MyTreeItemModel::flags(const QModelIndex &index) const
    {
    	if (!index.isValid())
    		return 0;
    
    	//The base class implementation returns a combination of flags that enables 
    	//the item (ItemIsEnabled) and allows it to be selected (ItemIsSelectable).
    	return QAbstractItemModel::flags(index);
    }
    
  8. boost::property_tree::ptree没有提供访问父节点的功能,故加了个GetParent函数,仅测试用,实际不应该这么用,效率低

    const boost::property_tree::ptree* MyTreeItemModel::GetParent(const boost::property_tree::ptree* pChild,
    	int& nParentRow) const
    {
    	if (!pChild)
    	{
    		return nullptr;
    	}
    
    	std::stack<const boost::property_tree::ptree*> mNodeStack;
    	mNodeStack.push(&m_TreeItem);
    	while (!mNodeStack.empty())
    	{
    		const boost::property_tree::ptree* pParent = mNodeStack.top();
    		mNodeStack.pop();
    		if (!pParent)
    		{
    			continue;
    		}
    
    		//在子节点列表中搜索指定节点
    		int nRow = 0;
    		for (auto it = pParent->begin(); it != pParent->end(); ++it, ++nRow)
    		{
    			const boost::property_tree::ptree* pChildItem = &(it->second);
    			if (pChildItem == pChild)
    			{
    				nParentRow = nRow;
    				return pParent;
    			}
    			
    			mNodeStack.push(pChildItem);
    		}
    	}
    
    	nParentRow = 0;
    	return nullptr;
    }
    

使用自写的模型类

QtGuiApplication1::QtGuiApplication1(QWidget *parent)
	: QMainWindow(parent)
{
	//ui.setupUi(this);

	auto pCentralWidget = new QWidget(this);
	this->setCentralWidget(pCentralWidget);

	auto pVLayout = new QVBoxLayout();
	QAbstractItemModel *pModel = new MyTreeItemModel();
	QTreeView *pTreeView = new QTreeView();
	pTreeView->setModel(pModel);
	pVLayout->addWidget(pTreeView);
	pCentralWidget->setLayout(pVLayout);
}

运行演示

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

论文 学习 Transformer : Attention Is All You Need

目录 概述&#xff1a; 对摘要的理解&#xff1a; 框架解析 按比例缩放的点积注意力 多头注意力机制 前馈神经网络与位置编码 概述&#xff1a; transformer 是一个encoder ——decoder 结构的用于处理序列到序列转换任务的框架&#xff0c;是第一个完全依赖自注意力机制…

基于Vue3与ElementUI Plus的酷企秀场景可视化DIY设计器探索(更新版)

一、引言 在当今数字化快速发展的时代&#xff0c;企业对于展示自身形象、产品细节以及提升客户体验的需求日益增强。酷企秀场景可视化DIY设计器&#xff0c;以其强大的功能和灵活的定制性&#xff0c;为企业提供了从VR全景展示到地图可视化、电子画册制作等一系列数字化解决方…

前端开发工程师——ajax

express框架 终端输入 npm init --yes npm i express 请求报文/响应报文 // 1.引入express const express require(express);// 2.创建应用对象 const app express();// 3.创建路由规则 // request:是对请求报文的封装 // response&#xff1a;是对响应报文的封装 app.get(…

基于Python的飞机大战游戏

学习目标 了解 飞机大战游戏的规则 理解 面向对象思想,会独立设计游戏的类与模块 掌握 pygame模块的使用 1.1 游戏介绍 飞机大战是一款由腾讯公司微信团队推出的软件内置的小游戏,这款游戏画面简洁有趣,规则简单易懂,操作简便易上手,在移动应用兴起之初曾风靡一时。 1.1.…

阿里云Redis创建使用

说明&#xff1a;本文介绍如何使用阿里云Redis&#xff0c;包括开通、连接、使用&#xff1b; 开通 进入官网Redis产品页&#xff0c;点击免费试用&#xff08;白嫖&#xff09;&#xff1b; 选择中间这个&#xff0c;云数据库Redis版&#xff1b; 开通完成后&#xff0c;可在…

JDBC调用MogDB存储过程返回ref_cursor的方法和注意事项

MogDB在处理存储过程的时候&#xff0c;有时候需要返回结果集&#xff0c;类型为ref_cursor&#xff0c;但有时候可能会报错。而大部分应用程序都是使用Java JDBC. 根据我们这几年的数据库国产化改造经验&#xff0c;给大家分享一下JDBC调用 MogDB存储过程返回ref_cursor的方法…

C#实现多线程的几种方式

前言 多线程是C#中一个重要的概念&#xff0c;多线程指的是在同一进程中同时运行多个线程的机制。多线程适用于需要提高系统并发性、吞吐量和响应速度的场景&#xff0c;可以充分利用多核处理器和系统资源&#xff0c;提高应用程序的性能和效率。 多线程常用场景 CPU 密集型任务…

书生浦语训练营第四次课作业

基础作业 环境配置 拷贝internlm开发机内的环境 studio-conda xtuner0.1.17# 激活环境 conda activate xtuner0.1.17 # 进入家目录 &#xff08;~的意思是 “当前用户的home路径”&#xff09; cd ~ # 创建版本文件夹并进入&#xff0c;以跟随本教程 mkdir -p /root/xtuner0…

社工库信息查询

此网站需要注册账号&#xff0c;新用户注册送3点券&#xff0c;每日签到可获得1.5点券。也可通过充值来查 我这里有方法可以利用缺陷来无限获取点券查人

QT7_视频知识点笔记_3_自定义控件,事件处理器⭐,定时器,QPainter,绘图设备,不规则窗口

第三天&#xff1a; 自定义控件&#xff0c;事件处理器⭐&#xff0c;定时器&#xff0c;QPainter,绘图设备&#xff0c;不规则窗口实现 1.自定义控件&#xff1a; 创建新的QT控件类&#xff0c;然后再需要使用的地方--》提升为 来使用如何使用基础控件的信号和槽函数&…

智能座舱语音助手产品方案

一、用户调研与痛点分析 1.目标用户分析 用户画像 性别女性年龄50地域2-3线城市职业退休或退居二线教育中专、 大专、 本科财务家庭财务管理者爱好享受生活、 照顾家庭标签有闲有小钱二、产品定位与卖点提炼 购车目的 愉悦自我&#xff0c; 专属于自己的座驾&#xff1a; 家…

【大数据·Hadoop】从词频统计由浅入深介绍MapReduce分布式计算的设计思想和原理

一、引入&#xff1a;词频统计问题 假如我们有一亿份文档&#xff0c;需要统计这一亿份文档的词频。我们会怎么做&#xff0c;有以下思路 使用单台PC执行&#xff1a;能不能存的下不说&#xff0c;串行计算&#xff0c;一份一份文档读&#xff0c;然后进行词频统计&#xff0…

最新版Ceph( Reef版本)文件存储简单对接k8s(下集)

假如ceph集群已经创建 1.创建cephfs_pool存储池 ceph osd pool create fs_kube_data 16 162.创建cephfs_metadata存储池 ceph osd pool create fs_kube_metadata 16 163 创建cephfs ceph fs new cephfs01 fs_kube_metadata fs_kube_data4 设置最大活动数 ceph fs set cephfs01…

保健品小程序商城线上经营的作用是什么

保健品涵盖酒水、醋、食品等多个类型&#xff0c;无论厂商还是经销商&#xff0c;手里的品牌和数量都比较多&#xff0c;由于特殊性&#xff0c;商家经营时需要找到目标客户&#xff0c;而市场中虽然有大量客户&#xff0c;但商家实际想要触达却并不容易。 渠道多样化&#xf…

MTEB - Embedding 模型排行榜

文章目录 关于 MTEBMTEB 任务和数据集概览使用 MTEB Pythont 库Installation使用 关于 MTEB MTEB : Massive Text Embedding Benchmark github : https://github.com/embeddings-benchmark/mtebhuggingface : https://huggingface.co/spaces/mteb/leaderboardpaper : https:/…

Java医院绩效考核系统源码B/S+avue+MySQL助力医院实现精细化管理 医院综合绩效核算系统源码

Java医院绩效考核系统源码B/SavueMySQL助力医院实现精细化管理 医院综合绩效核算系统源码 医院绩效考核系统目标是实现对科室、病区财务指标、客户指标、流程指标、成长指标的全面考核、分析&#xff0c;并与奖金分配、学科建设水平评价挂钩。 具体功能模块包括收入核算、成本…

(超简单)SpringBoot中简单用工厂模式来实现

简单讲述业务需求 业务需要根据不同的类型返回不同的用户列表&#xff0c;比如按角色查询用户列表、按机构查询用户列表&#xff0c;用户信息需要从数据库中查询&#xff0c;因为不同的类型查询的逻辑不相同&#xff0c;因此简单用工厂模式来设计一下&#xff1b; 首先新建一个…

安装SQL Server详细教程_sql server安装教程

一&#xff0c;SQL Server数据库安装 1.首先&#xff0c;下载安装程序 &#xff08;1&#xff09;从网盘下载安装exe 点击此处直接下载 &#xff08;2&#xff09;从官网下载安装exe文件 在官网选择Developer进行下载 2.开始安装 双击安装程序&#xff0c;开始安装 这里直…

springboot(3.2.5)初步集成MinIO(8.5.9)开发记录

springboot初步集成MinIO开发记录 说明一&#xff1a;引入maven依赖二&#xff1a;手动注入minioClient三&#xff1a;创建service类四&#xff1a;测试打印连接信息五&#xff1a;时区转化工具类六&#xff1a;常用操作演示 说明 这里只是作者开发的记录&#xff0c;已备将来…

程序人生 | 人生如棋,落子无悔

人生的开始&#xff0c;始于哭声&#xff0c;浮浮沉沉几十年。终了&#xff0c;一声长叹&#xff0c;在一片哭声中撒手离去。 人生的道路虽然漫长&#xff0c;但是关键就是那么几次机会的选择&#xff0c;可以决定此后几十年的光阴。 有个故事讲&#xff1a;古代有个人去砍柴…