当前位置:网站首页>QT的Tree View Model示例
QT的Tree View Model示例
2022-07-25 22:40:00 【物随心转】
一、介绍
使用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博客
边栏推荐
- Platform architecture construction
- Examples and points for attention about the use of getchar and scanf
- 编译器引论
- Xiaobai programmer's seventh day
- torchvision
- 【数据库学习】Redis 解析器&&单线程&&模型
- Von Neumann architecture
- Today, let's talk about the if branch statement of the selection structure
- Arcgis10.2 configuring postgresql9.2 standard tutorial
- Explore the use of self increasing and self decreasing operators
猜你喜欢

Data quality: the core of data governance

【集训DAY13】Internet【并查集】

Xiaobai programmer day 8

【集训DAY15】简单计算【树状数组】【数学】

Naming rules of software test pytest pytest the pre and post confitest of use cases Py customized allure report @pytest.mark.parameter() decorator as data-driven

面试题 17.11. 单词距离 ●●

(1) DDL, DML, DQL, DCL and common data types

JVM内存区域

Method of converting MAPGIS format to ArcGIS

Basic principle of torque motor control
随机推荐
Platform architecture construction
JSON object
Naming rules of software test pytest pytest the pre and post confitest of use cases Py customized allure report @pytest.mark.parameter() decorator as data-driven
自媒体人必备的4个资源工具,每一个都很实用
Domain oriented model programming
[training Day11] Calc [mathematics]
3 词法分析
Data type conversion
Severely crack down on illegal we media operators according to law: it is urgent to purify the we media industry
DOM event binding
【PMP学习笔记】第1章 PMP体系引论
To light up all the positions in the string that need to be lit, at least a few lights are needed
依法严厉打击违规自媒体运营者:净化自媒体行业迫在眉睫
【集训DAY12】X equation 【高精度】【数学】
IPv4地址已经完全耗尽,互联网还能正常运转,NAT是最大功臣!
Binder principle
ThreadLocal summary (to be continued)
Ffmpeg plays audio and video, time_ Base solves the problem of audio synchronization and SDL renders the picture
xss-工具-Beef-Xss安装以及使用
JD quick navigation box