1、TreeViewItem.h
#pragma once
#include <QList>
class TreeViewItem
{
public: TreeViewItem(const QList<QVariant>& data, TreeViewItem* parent = NULL);
~TreeViewItem();
void appendChild(TreeViewItem* child);
void deleteAllChild();
TreeViewItem* child(int row);
int childCount() const;
int columnCount() const;
QVariant data(int column) const;
void setParent(TreeViewItem* parent);
TreeViewItem* parent();
int row() const;
private:
TreeViewItem* m_parentItem;
QList<TreeViewItem*> m_childItems;
QList<QVariant> m_itemData;
};
2、TreeViewItem.cpp
#include "TreeViewItem.h"
TreeViewItem::TreeViewItem(const QList<QVariant>& data, TreeViewItem* parent)
{
this->m_itemData = data;
this->m_parentItem = parent;
}TreeViewItem::~TreeViewItem()
{
this->m_itemData.clear();
this->m_parentItem = NULL;
}void TreeViewItem::appendChild(TreeViewItem* child)
{
child->setParent(this);
this->m_childItems.append(child);
}void TreeViewItem::deleteAllChild()
{
for (int index = 0; index < m_childItems.size(); index++)
{
m_childItems[index]->deleteAllChild();
}
qDeleteAll(m_childItems);
m_childItems.clear();
}TreeViewItem* TreeViewItem::child(int row)
{
return m_childItems[row];
}int TreeViewItem::childCount() const
{
return m_childItems.size();
}int TreeViewItem::columnCount() const
{
return m_itemData.size();
}QVariant TreeViewItem::data(int column) const
{
return m_itemData[column];
}void TreeViewItem::setParent(TreeViewItem* parent)
{
m_parentItem = parent;
}TreeViewItem* TreeViewItem::parent()
{
return m_parentItem;
}int TreeViewItem::row() const
{
if (!m_parentItem) { return 0; } return m_parentItem->m_childItems.indexOf(const_cast<TreeViewItem*>(this));
}
3、TreeViewModel.h
#pragma once
#ifndef TREEVIEWMODEL_H
#define TREEVIEWMODEL_H#include <QAbstractItemModel>
#include <QObject>
#include <QDebug>
#include "TreeViewItem.h"#pragma execution_character_set("utf-8")
class TreeViewModel : public QAbstractItemModel
{
Q_OBJECTpublic:
TreeViewModel(); ~TreeViewModel();
void setHeaders(const QStringList& headers)
{
m_headers = headers;
} void setTreeViewRootItem(TreeViewItem* rootItem)
{
m_rootItem = rootItem;
} // 必须要重写的五个函数
Q_INVOKABLE QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override; Q_INVOKABLE QModelIndex parent(const QModelIndex& child) const override;
Q_INVOKABLE int rowCount(const QModelIndex& parent = QModelIndex()) const override;
Q_INVOKABLE int columnCount(const QModelIndex& parent = QModelIndex()) const override;
Q_INVOKABLE QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
private:
TreeViewItem* itemFromIndex(const QModelIndex& index) const;
private:
TreeViewItem* m_rootItem;
QStringList m_headers;
};#endif // TREEVIEWMODEL_H
4、TreeViewModel.cpp
#include "TreeViewModel.h"
TreeViewModel::TreeViewModel()
{
m_rootItem = nullptr;
m_headers.clear();
}TreeViewModel::~TreeViewModel()
{
m_rootItem->deleteAllChild();
m_rootItem = NULL;
}QModelIndex TreeViewModel::index(int row, int column, const QModelIndex& parent) const
{
if (!hasIndex(row, column, parent))
{
return QModelIndex();
} TreeViewItem* treeItem = itemFromIndex(parent);
TreeViewItem* child = treeItem->child(row); // 第几行就是第几个子节点,TreeView一般都是一行一个节点的
if (child) {
return createIndex(row, column, child);
}
else {
return QModelIndex();
}}
// 返回给定项目的父项目
QModelIndex TreeViewModel::parent(const QModelIndex& child) const
{
if (!child.isValid())
{
return QModelIndex();
} TreeViewItem* childItem = static_cast<TreeViewItem*>(child.internalPointer());
TreeViewItem* parentItem = childItem->parent(); if (parentItem == m_rootItem)
{
return QModelIndex();
} return createIndex(parentItem->row(), 0, parentItem);
}// 返回给定项目的行数
int TreeViewModel::rowCount(const QModelIndex& parent) const
{
if (parent.column() > 0)
return 0; TreeViewItem* item = itemFromIndex(parent);
return item->childCount();
}// 返回给定项目的列数
int TreeViewModel::columnCount(const QModelIndex& parent) const
{
if (m_headers.isEmpty())
{
// 返回实际的列数 (实际是他返回了0,因为根节点用的是无参的构造),TreeView控件会认为表是空表,不获取数据
if (parent.isValid())
{
return static_cast<TreeViewItem*>(parent.internalPointer())->columnCount();
}
else {
return m_rootItem->columnCount();
}
}
else
{
return m_headers.size();
}
}QVariant TreeViewModel::data(const QModelIndex& index, int role) const
{
if (!index.isValid())
return QVariant(); TreeViewItem* item = itemFromIndex(index);
if (role == Qt::DisplayRole)
{
return item->data(index.column());
}
else if (role == Qt::FontRole)
{
}
else if (role == Qt::TextColorRole)
{
}
else if (role == Qt::BackgroundRole)
{
}
else if (role == Qt::TextAlignmentRole)
{
}
return QVariant();
}// 获取父节点的数据指针,如果parent可用就用parent的节点,如果不可用就用总父节点
TreeViewItem* TreeViewModel::itemFromIndex(const QModelIndex& parent) const
{
if (parent.isValid())
{
// internalPointer: 返回一个void *指针,用于模型将索引与内部数据结构关联起来
TreeViewItem* item = static_cast<TreeViewItem*>(parent.internalPointer());
return item;
}
return m_rootItem;
}
调用实例:
{
TreeViewModel* model = new TreeViewModel();
QStringList headers;
headers << "1" << "2";
model->setHeaders(headers); QVariantList lstVariant;
TreeViewItem* pRootItem = new TreeViewItem(lstVariant);
{
lstVariant.clear();
lstVariant << "1" << "第一章";
TreeViewItem* pItem1 = new TreeViewItem(lstVariant);
pRootItem->appendChild(pItem1);
}
{
lstVariant.clear();
lstVariant << "2" << "第二章";
TreeViewItem* pItem2 = new TreeViewItem(lstVariant);
pRootItem->appendChild(pItem2);
}
model->setTreeViewRootItem(pRootItem); ui.treeView->setModel(model);
}
效果如下所示: