当前位置:网站首页>QTreeView+自定义Model实现示例
QTreeView+自定义Model实现示例
2022-07-04 09:32:00 【班公湖里洗过脚】
QTreeView是用来显示树型结构的数据,比如目录组织,公司组织架构等,数据量小可以用Qt自带的Model实现,如果数据量大,则需要用自定义的Model实现,下面介绍自定义实现的方法,直接上代码:
#ifndef TYPEDEF_H
#define TYPEDEF_H
#include <QVector>
// department信息
typedef struct Department_t{
QString name; // 部门名称
int id; // 部门id号
int number; // 部门人数
QString preOrganizationName; // 上级组织名
Department_t()
{
id = 0;
number = 0;
}
QVector<Department_t*> subList;
} Department;
// 树列号
enum COLUMN
{
COLUMN_NAME = 0,
COLUMN_ID,
COLUMN_NUM,
COLUMN_OrganizationName
};
#endif // TYPEDEF_H
#ifndef TREEITEM_H
#define TREEITEM_H
#include <QVariant>
class TreeItem
{
public:
enum Type
{
UNKNOWN = -1,
PROVINCE,
PERSON
};
explicit TreeItem(TreeItem *parent = nullptr);
~TreeItem();
void addChild(TreeItem *item);
void removeChildren();
TreeItem *child(int row) { return _children.value(row); }
TreeItem *parent() { return _parent; }
int childCount() const { return _children.count(); }
QVariant data(int column) const;
//设置、获取节点存的数据指针
void setPtr(void* p) { _ptr = p; }
void* ptr() const { return _ptr; }
// 保存该节点是其父节点的第几个子节点,查询优化所用
void setRow(int row) { _row = row; }
// 返回本节点位于父节点下第几个子节点
int row() const { return _row; }
Type getType() const { return _type; }
void setType(const Type &value) { _type = value; }
private:
QList<TreeItem*> _children; // 子节点
TreeItem *_parent; // 父节点
Type _type; // 此节点保存的数据类型
void* _ptr; // 存储数据的指针
int _row; // 此item位于父节点中第几个
};
#endif // TREEITEM_H
#include "TreeItem.h"
#include "typedef.h"
TreeItem::TreeItem(TreeItem *parent)
: _parent(parent),
_type(UNKNOWN),
_ptr(nullptr),
_row(-1)
{
}
TreeItem::~TreeItem()
{
removeChildren();
}
// 在本节点下添加子节点
void TreeItem::addChild(TreeItem *item)
{
item->setRow(_children.size());
_children.append(item);
}
// 清空所有子节点
void TreeItem::removeChildren()
{
qDeleteAll(_children);
_children.clear();
}
// 获取本节点第column列的数据
QVariant TreeItem::data(int column) const
{
Department *department = (Department*)_ptr;
switch (column) {
case COLUMN_NAME: return department->name;
case COLUMN_ID: return department->id;
case COLUMN_NUM: return department->number;
case COLUMN_OrganizationName: return department->preOrganizationName;
default:return QVariant();
}
return QVariant();
}
#ifndef TREEMODEL_H
#define TREEMODEL_H
#include <QAbstractItemModel>
class TreeItem;
class TreeModel : public QAbstractItemModel
{
Q_OBJECT
public:
explicit TreeModel(const QStringList& headers, QObject *parent = nullptr);
~TreeModel() override;
TreeItem *root();
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
QVariant data(const QModelIndex &index, int role) const override;
QModelIndex index(int row, int column, const QModelIndex &parent) const override;
QModelIndex parent(const QModelIndex &index) const override;
int rowCount(const QModelIndex &parent) const override;
int columnCount(const QModelIndex &parent) const override;
private:
TreeItem *itemFromIndex(const QModelIndex &index) const;
private:
QStringList _headers;
TreeItem* _rootItem;
};
#endif // TREEMODEL_H
#include "TreeModel.h"
#include "TreeItem.h"
TreeModel::TreeModel(const QStringList& headers, QObject *parent)
: QAbstractItemModel(parent)
{
_headers = headers;
_rootItem = new TreeItem();
}
TreeModel::~TreeModel()
{
delete _rootItem;
}
TreeItem *TreeModel::itemFromIndex(const QModelIndex &index) const
{
if (index.isValid())
{
TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
return item;
}
return _rootItem;
}
TreeItem *TreeModel::root()
{
return _rootItem;
}
// 获取表头数据
QVariant TreeModel::headerData(int section, Qt::Orientation orientation,int role) const
{
if (orientation == Qt::Horizontal)
{
if(role == Qt::DisplayRole)
{
return _headers.at(section);
}
}
return QVariant();
}
// 获取index.row行,index.column列数据
QVariant TreeModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
TreeItem *item = itemFromIndex(index);
if (role == Qt::DisplayRole)
{
return item->data(index.column());
}
return QVariant();
}
// 在parent节点下,第row行,第column列位置上创建索引
QModelIndex TreeModel::index(int row, int column, const QModelIndex &parent) const
{
if (!hasIndex(row, column, parent))
return QModelIndex();
TreeItem *parentItem = itemFromIndex(parent);
TreeItem *item = parentItem->child(row);
if (item)
return createIndex(row, column, item);
else
return QModelIndex();
}
// 创建index的父索引
QModelIndex TreeModel::parent(const QModelIndex &index) const
{
if (!index.isValid())
return QModelIndex();
TreeItem *item = itemFromIndex(index);
TreeItem *parentItem = item->parent();
if (parentItem == _rootItem)
return QModelIndex();
return createIndex(parentItem->row(), 0, parentItem);
}
// 获取索引parent下有多少行
int TreeModel::rowCount(const QModelIndex &parent) const
{
if (parent.column() > 0)
return 0;
TreeItem* item = itemFromIndex(parent);
return item->childCount();
}
// 返回索引parent下有多少列
int TreeModel::columnCount(const QModelIndex &parent) const
{
return _headers.size();
}
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include <QTreeView>
#include <QHeaderView>
#include <QFile>
#include <QJsonObject>
#include <QJsonDocument>
#include <QJsonArray>
#include "TreeModel.h"
#include "TreeItem.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
treeView = new QTreeView(this);
treeView->setSelectionBehavior(QTreeView::SelectRows); //一次选中整行
treeView->setSelectionMode(QTreeView::SingleSelection); //单选,配合上面的整行就是一次选单行
treeView->setFocusPolicy(Qt::NoFocus); //去掉鼠标移到单元格上时的虚线框
treeView->header()->setStretchLastSection(true); //最后一列自适应宽度
//treeView->setHeaderHidden(true); //设置表头隐藏
setCentralWidget(treeView);
QVector<Department*> proList = initData();
setModel(proList);
}
MainWindow::~MainWindow()
{
delete ui;
}
QVector<Department*> MainWindow::initData()
{
QFile file(":/default2.txt");
file.open(QIODevice::ReadOnly);
QJsonDocument doc = QJsonDocument::fromJson(file.readAll());
QJsonObject obj = doc.object();
QJsonArray array = obj.value("nextLevel").toArray();
QVector<Department*> depList;
qDebug() << "TreeModel::setupModelDataJson==============array.size()====" << array.size() << __LINE__;
for(int i = 0; i < array.size(); ++i)
{
QJsonObject subObject = array.at(i).toObject();
QJsonArray subArray = subObject.value("nextLevel").toArray();
Department *topDepartment = new Department();
topDepartment->id = subObject.value("id").toInt();
topDepartment->name = subObject.value("name").toString();
topDepartment->number = subObject.value("nnt").toInt();
topDepartment->preOrganizationName = subObject.value("preOrganizationName").toString();
qDebug() << "TreeModel::setupModelDataJson==============subArray.size()====" << subArray.size() << __LINE__;
//第二级
for(int i = 0; i < subArray.size(); ++i)
{
QJsonObject tempObj = subArray.at(i).toObject();
Department *subDepartment = new Department();
subDepartment->id = tempObj.value("id").toInt();
subDepartment->name = tempObj.value("name").toString();
subDepartment->number = tempObj.value("nnt").toInt();
subDepartment->preOrganizationName = tempObj.value("preOrganizationName").toString();
topDepartment->subList.append(subDepartment);
}
depList.append(topDepartment);
}
return depList;
}
void MainWindow::setModel(const QVector<Department *> &depList)
{
QStringList headers;
headers << QStringLiteral("部门名称")
<< QStringLiteral("部门Id")
<< QStringLiteral("部门人数")
<< QStringLiteral("上级部门");
TreeModel* model = new TreeModel(headers, treeView);
TreeItem* root = model->root();
foreach (auto depNode, depList)
{
TreeItem* depItem = new TreeItem(root);
depItem->setPtr(depNode); // 保存数据指针
root->addChild(depItem);
foreach (auto subNode, depNode->subList)
{
TreeItem* subItem = new TreeItem(depItem);
subItem->setPtr(subNode); // 保存数据指针
depItem->addChild(subItem);
}
}
treeView->setModel(model);
}
运行结果:
参考:
《QTreeView+QAbstractItemModel自定义模型》:系列教程之三_百里杨的博客-CSDN博客_qtreeview自定义
QTreeView使用总结13,自定义model示例,大大优化性能和内存_逆枫゛的博客-CSDN博客_qtreeview用法
Qt 自定义treemodel_sydnash的博客-CSDN博客_qt自定义treemodel
Qt 可编辑的树模型(Tree Model)的一个实例_qq_21291397的博客-CSDN博客_pyqt treemodel
Qt QTreeView 详解_Mr.codeee的博客-CSDN博客_qt treeview
QJsonObject和QString互转_风起时~微凉的博客-CSDN博客_qjsonobject转qstring
完整源码和测试数据
QTreeView+自定义Model实现示例-C++文档类资源-CSDN下载
边栏推荐
- 《网络是怎么样连接的》读书笔记 - FTTH
- Luogu deep foundation part 1 Introduction to language Chapter 4 loop structure programming (2022.02.14)
- You can see the employment prospects of PMP project management
- C语言-入门-基础-语法-数据类型(四)
- The old-fashioned synchronized lock optimization will make it clear to you at once!
- 2022-2028 global intelligent interactive tablet industry research and trend analysis report
- 2022-2028 global probiotics industry research and trend analysis report
- C语言-入门-基础-语法-[标识符,关键字,分号,空格,注释,输入和输出](三)
- Awk from getting started to digging in (11) detailed explanation of awk getline function
- Flutter 小技巧之 ListView 和 PageView 的各種花式嵌套
猜你喜欢
LeetCode 74. Search 2D matrix
C语言-入门-基础-语法-[主函数,头文件](二)
C语言-入门-基础-语法-[运算符,类型转换](六)
2022-2028 global small batch batch batch furnace industry research and trend analysis report
CLion-控制台输出中文乱码
C language - Introduction - Foundation - syntax - [main function, header file] (II)
How do microservices aggregate API documents? This wave of show~
Function comparison between cs5261 and ag9310 demoboard test board | cost advantage of cs5261 replacing ange ag9310
2022-2028 global edible probiotic raw material industry research and trend analysis report
At the age of 30, I changed to Hongmeng with a high salary because I did these three things
随机推荐
Global and Chinese markets of hemoglobin analyzers in care points 2022-2028: Research Report on technology, participants, trends, market size and share
Target detection -- intensive reading of yolov3 paper
What is uid? What is auth? What is a verifier?
MySQL transaction mvcc principle
Reload CUDA and cudnn (for tensorflow and pytorch) [personal sorting summary]
2022-2028 global probiotics industry research and trend analysis report
Logstack configuration details -- elasticstack (elk) work notes 020
Launpad | 基礎知識
Daughter love in lunch box
After unplugging the network cable, does the original TCP connection still exist?
PMP registration process and precautions
Research Report on research and investment prospects of China's testing machine industry (2022 Edition)
The old-fashioned synchronized lock optimization will make it clear to you at once!
2022-2028 global gasket plate heat exchanger industry research and trend analysis report
You can see the employment prospects of PMP project management
Explanation of for loop in golang
How should PMP learning ideas be realized?
Investment analysis and future production and marketing demand forecast report of China's paper industry Ⓥ 2022 ~ 2028
Flutter tips: various fancy nesting of listview and pageview
UML 时序图[通俗易懂]