首先需要知道展示基本的树需要重写QAbstrctItemModel继承类的这5个函数。至少完成这个五个函数的实现才会展示数据
// Header:
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;
//节点的行列(m,n)
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
//显示数据
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
基于model and view 加上data完成了一个特殊的结构就是数据视图分离这和java中说的MVC相似。
这样的好处是我们可以随意处理自己的数据。
构建模型步骤
1.数据结构Item可以用结构体或者类来定义这个项基本的数据结构。项包含了当前的展示数据,父节点和孩子节点列表。需要定义获取项数据的函数。
TreeItem.h
#ifndef TREEITEM_H
#define TREEITEM_H
#include<QtCore>
class TreeItem
{
public:
TreeItem();
QVariant getData() const;
bool setData(const QVariant &value);
//得到当前节点孩子的数量
int getChildrenCount() const;
void addChildren(TreeItem *node);
TreeItem*getChild(int row);
TreeItem *getPrent() const;
//得到当前项的索引
int getCurrentRow();
private:
QVariant m_data;
QList<TreeItem*> m_children;
TreeItem*m_prent=nullptr;
};
#endif // TREEITEM_H
TreeItem.cpp
#include "TreeItem.h"
TreeItem::TreeItem()
{
}
QVariant TreeItem::getData() const
{
return m_data;
}
bool TreeItem::setData(const QVariant &value)
{
if(value.isNull()||value=="")return false;
if(value.isValid())
{
m_data = value;
return true;
}
return false;
}
int TreeItem::getChildrenCount() const
{
return m_children.count();
}
void TreeItem::addChildren(TreeItem *node)
{
m_children.append(node);
}
TreeItem *TreeItem::getChild(int row)
{
return m_children.at(row);
}
TreeItem *TreeItem::getPrent() const
{
return m_prent;
}
int TreeItem::getCurrentRow()
{
if(m_prent)
return m_prent->m_children.indexOf(const_cast<TreeItem*>(this));
return 0;
}
2.数据源Data这部分用来组织树的结构同时也可以和文件或数据库交互,数据源通常是单例的。当然案例是内存中的,当也是视图模型分离的。
TreeData.h
#ifndef TREEDATA_H
#define TREEDATA_H
#include"TreeItem.h"
class TreeData
{
public:
TreeData();
TreeItem *getRootNode() const;
static TreeData*getInstence();
private:
TreeItem *rootNode=nullptr;
};
#endif // TREEDATA_H
TreeData.cpp
#include "TreeData.h"
TreeData::TreeData()
{
//root
QString rootData="root";
rootNode=new TreeItem();
rootNode->setData(rootData);
//root child
QString first="first";
TreeItem*first_node=new TreeItem();
first_node->setData(first);
first_node->setPrent(rootNode);
rootNode->addChildren(first_node);
QString first_1="first_1";
TreeItem*first_node_1=new TreeItem();
first_node_1->setData(first);
first_node_1->setPrent(first_node);
first_node->addChildren(first_node_1);
QString first_2="first_2";
TreeItem*first_node_2=new TreeItem();
first_node_2->setData(first_2);
first_node_2->setPrent(first_node);
first_node->addChildren(first_node_2);
//root child
QString scond="scond";
TreeItem*scond_node=new TreeItem();
scond_node->setData(scond);
scond_node->setPrent(rootNode);
rootNode->addChildren(scond_node);
QString scond_1="scond_1";
TreeItem*scond_node_1=new TreeItem();
scond_node_1->setData(scond_1);
scond_node_1->setPrent(scond_node);
scond_node->addChildren(scond_node_1);
QString scond_2="scond_2";
TreeItem*scond_node_2=new TreeItem();
scond_node_2->setData(scond_2);
scond_node_2->setPrent(scond_node);
scond_node->addChildren(scond_node_2);
}
TreeItem *TreeData::getRootNode() const
{
return rootNode;
}
TreeData*TreeData::getInstence()
{
static TreeData treeData;
return &treeData;
}
3.视图模型,treeview直接获取的数据模型
TreeViewModel.h
#ifndef TREEVIEWMODEL_H
#define TREEVIEWMODEL_H
#include <QAbstractItemModel>
#include"TreeItem.h"
class TreeViewModel : public QAbstractItemModel
{
Q_OBJECT
public:
explicit TreeViewModel(QObject *parent = nullptr);
// Header:
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;
//节点的行列(m,n)
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
//显示数据
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
//是否可编辑
Qt::ItemFlags flags(const QModelIndex &index) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
private:
TreeItem*m_rootNode=nullptr;
};
#endif // TREEVIEWMODEL_H
TreeViewModel.cpp
#include "TreeViewModel.h"
#include"TreeData.h"
TreeViewModel::TreeViewModel(QObject *parent)
: QAbstractItemModel(parent)
{
m_rootNode=TreeData::getInstence()->getRootNode();
}
QVariant TreeViewModel::headerData(int section, Qt::Orientation orientation, int role) const
{
Q_UNUSED(section)
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
return m_rootNode->getData();
return QVariant();
}
QModelIndex TreeViewModel::index(int row, int column, const QModelIndex &parent) const
{
if(!m_rootNode)
return QModelIndex();
if (!this->hasIndex(row, column, parent))
return QModelIndex();
if (!parent.isValid())
return createIndex(row, column, m_rootNode);
TreeItem *parentItem =static_cast<TreeItem*>(parent.internalPointer());;
if(parentItem==nullptr)
return QModelIndex();
TreeItem *childItem = parentItem->getChild(row);
if(childItem==nullptr)
return QModelIndex();
return createIndex(row, column, childItem);
}
QModelIndex TreeViewModel::parent(const QModelIndex &index) const
{
if(!m_rootNode)
return QModelIndex();
if (!index.isValid())
return QModelIndex();
TreeItem* nodeItem = static_cast<TreeItem*>(index.internalPointer()); // get parent node
nodeItem = nodeItem->getPrent();
if (nodeItem == nullptr)
return QModelIndex();
int row = nodeItem->getCurrentRow(); // get parent index
return createIndex(row, 0, nodeItem);
}
int TreeViewModel::rowCount(const QModelIndex &parent) const
{
if (!parent.isValid())
return 1;
TreeItem* pNode = static_cast<TreeItem*>(parent.internalPointer());
return pNode->getChildrenCount();
}
int TreeViewModel::columnCount(const QModelIndex &parent) const
{
Q_UNUSED(parent)
return 1;
}
QVariant TreeViewModel::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->getData();
}
Qt::ItemFlags TreeViewModel::flags(const QModelIndex& index) const
{
if (!index.isValid())
return 0;
return Qt::ItemIsEditable | QAbstractItemModel::flags(index);
}
bool TreeViewModel::setData(const QModelIndex& index, const QVariant& value, int role)
{
if (role != Qt::EditRole)
return false;
if(!index.isValid())
return false;
TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
bool result =item->setData(value);
if (result)
emit dataChanged(index, index);
return result;
}
TreeView.cpp
TreeViewModel *model=new TreeViewModel(this);
ui->treeView->setModel(model);
上面是自定义的单列树节点:
效果如下
多列的节点请参考:
https://blog.csdn.net/hp_cpp/article/details/96486104?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522162374026016780265484949%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=162374026016780265484949&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2blogfirst_rank_v2~rank_v29-2-96486104.nonecase&utm_term=QT+Treeview&spm=1018.2226.3001.4450
网友评论