上文已经介绍过二维表模型的实现方式,接着分享层次模型的实现,首先实现一个节点类用于保存树状数据模型的节点数据和节点关系:
-
class TreeNode;
-
-
typedef TreeNode* TreeNodePtr;
-
-
class TreeNode
-
{
-
public:
-
explicit TreeNode();
-
TreeNodePtr parent() const;
-
void setParent(const TreeNodePtr p); //设置父节点,根节点的父节点为NULL
-
void appendNode(TreeNodePtr node);
-
void removeNode(int row);
-
void setData(int role,QVariant value);
-
QList<TreeNodePtr>childs; //用于保存子节点指针,把childs放到public不好,仅仅是为了方便,不要学。
-
-
private:
-
TreeNodePtr mParent=NULL; //父节点
-
QHash<int,QVariant>mRecord; //一个节点可以保存一行数据,哈希表的key是整型,用于保存role,QVariant保存数据
-
-
};
TreeNode的实现也是相当简单:
-
TreeNodePtr TreeNode::parent() const
-
{
-
return mParent;
-
}
-
-
void TreeNode::setParent(const TreeNodePtr p)
-
{
-
this->mParent = p;
-
}
-
-
void TreeNode::appendNode(TreeNodePtr node)
-
{
-
childs.append(node);
-
}
-
-
void TreeNode::removeNode(int row)
-
{
-
childs.removeAt(row);
-
}
-
-
-
QVariant TreeNode::data(int role)
-
{
-
return mRecord[role];
-
}
-
-
void TreeNode::setData(int role, QVariant value)
-
{
-
mRecord[role] = value;
-
}
接下来开始对SqlMenuEntryModel进行手术:
-
class SqlMenuEntry:public QAbstractItemModel,public QQmlParserStatus
-
{
-
Q_OBJECT
-
public:
-
explicit SqlMenuEntry(QObject *parent=0);
-
~SqlMenuEntry();
-
enum MenuEntryRoles{idRole=Qt::UserRole+1,nameRole,defaultEntryRole,customEntryRole,iconRole,iconHoverRole};
-
int rowCount(const QModelIndex &parent=QModelIndex()) const;
-
int columnCount(const QModelIndex &parent=QModelIndex()) const;
-
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const;
-
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const;
-
QModelIndex parent(const QModelIndex &child) const;
-
QHash<int,QByteArray>roleNames() const;
-
private:
-
QHash<int,QByteArray> mRoleNames;
-
QList<QHash<int,QVariant>> mRecords; //QList不能保存树状数据,干掉
-
QList mRootEntrys; //用于保存根节点
-
void _addEntryNode(TreeNodePtr node,TreeNodePtr parent=0); //用于向树添加节点
-
};
_addEntryNode的实现如下:
-
void SqlMenuEntry::_addEntryNode(TreeNodePtr node, TreeNodePtr parent)
-
{
-
if(parent == NULL)
-
{
-
mRootEntrys.append(node);
-
}else{
-
node->setParent(parent);
-
parent->appendNode(node);
-
}
-
}
-
可以通过如下代码向模型添加数据:
-
beginResetModel();
-
-
auto node = new TreeNode();
-
node->setData(nameRole,"parent 1");
-
node->setData(iconRole,"parent icon1");
-
_addEntryNode(node); //添加第一个根节点
-
-
auto subNode = new TreeNode();
-
subNode->setData(nameRole,"child 1");
-
_addEntryNode(subNode,node); //添加子节点
-
-
endResetModel();
上面的代码向模型添加了一个根节点parent1和parent1的一个子节点child1,接下来可以对SqlMenuEntryModel进行持续改进,让TreeView可以顺利显示正确的数据和数据关系。首先,更改int rowCount(const QModelIndex &parent)让模型可以正确的返回根节点数和子节点行数:
-
int SqlMenuEntry::rowCount(const QModelIndex &parent) const
-
{
-
if(parent.isValid()) //parent不为空,则要获取的行数是某个节点的子节点行数
-
{
-
TreeNodePtr parentNode = (TreeNodePtr)parent.internalPointer(); //节点信息在index时被保存在QModelIndex的internalPointer中
-
return parentNode->childs.size();
-
}
-
return mRootEntrys.size(); //否则返回的是根节点行数
-
-
}
实现index接口函数,让模型可以返回子节点的modelIndex同时将对应的节点指针保存在modelIndex的internalPointer中:
-
QModelIndex SqlMenuEntry::index(int row, int column, const QModelIndex &parent) const
-
{
-
if(!parent.isValid()) //parent为空,返回的是根节点的modelIndex,返回的同时,把节点数据指针(TreeNodePtr)保存在QModelIndex的internalPointer中,以便在其它函数中获取节点数据
-
{
-
if((row >= 0) && (row < mRootEntrys.size()))
-
{
-
return createIndex(row,column,mRootEntrys.at(row));
-
}
-
}else{
-
TreeNodePtr parentNode = (TreeNodePtr)parent.internalPointer(); //返回子节点的modelIndex
-
return createIndex(row,column,parentNode->childs[row]);
-
}
-
return QModelIndex();
-
}
parent(const QModelIndex &child) 用于返回一个节点的父节点索引:
-
QModelIndex SqlMenuEntry::parent(const QModelIndex &child) const
-
{
-
TreeNodePtr node = (TreeNodePtr)child.internalPointer();
-
if(node->parent() == NULL)
-
{
-
return QModelIndex(); //根节点没有parent
-
}else{
-
return createIndex(0,1,node->parent());
-
}
实现
data(const QModelIndex &index, int role) 返回节点中的数据:
-
QVariant SqlMenuEntry::data(const QModelIndex &index, int role) const
-
{
-
TreeNodePtr node = (TreeNodePtr)index.internalPointer();
-
return node->data(role);
-
}
经过上面的打造,模型已经可以正常为TreeView提供数据:
-
TreeView{
-
anchors.fill: parent
-
TableViewColumn {
-
title: "Name"
-
role: "name"
-
}
-
-
TableViewColumn {
-
title: "Entry"
-
role: "icon"
-
}
-
model:MenuEntryModel{}
-
}
继续干活去了,明天再继续补充数据添加、删除和更新的相关经验。
阅读(25573) | 评论(0) | 转发(0) |