使用C++实现QML的TreeView Model (二)_PHP教程
程序员文章站
2022-05-06 14:59:13
...
使用C++实现QML的TreeView Model (二)
上文已经介绍过二维表模型的实现方式,接着分享层次模型的实现,首先实现一个节点类用于保存树状数据模型的节点数据和节点关系:TreeNode的实现也是相当简单:
- 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
childs; //用于保存子节点指针,把childs放到public不好,仅仅是为了方便,不要学。 - private:
- TreeNodePtr mParent=NULL; //父节点
- QHash
mRecord; //一个节点可以保存一行数据,哈希表的key是整型,用于保存role,QVariant保存数据 - };
接下来开始对SqlMenuEntryModel进行手术:
- 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;
- }
_addEntryNode的实现如下:
- 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
roleNames() const; - private:
- QHash
mRoleNames; QListQHashint,QVariant>>mRecords;//QList不能保存树状数据,干掉- QList mRootEntrys; //用于保存根节点
- void _addEntryNode(TreeNodePtr node,TreeNodePtr parent=0); //用于向树添加节点
- };
可以通过如下代码向模型添加数据:
- void SqlMenuEntry::_addEntryNode(TreeNodePtr node, TreeNodePtr parent)
- {
- if(parent == NULL)
- {
- mRootEntrys.append(node);
- }else{
- node->setParent(parent);
- parent->appendNode(node);
- }
- }
上面的代码向模型添加了一个根节点parent1和parent1的一个子节点child1,接下来可以对SqlMenuEntryModel进行持续改进,让TreeView可以顺利显示正确的数据和数据关系。首先,更改int rowCount(const QModelIndex &parent)让模型可以正确的返回根节点数和子节点行数:
- beginResetModel();
- auto node = new TreeNode();
- node->setData(nameRole,"parent 1");
- node->setData(iconRole,"parenticon1");
- _addEntryNode(node); //添加第一个根节点
- auto subNode = new TreeNode();
- subNode->setData(nameRole,"child1");
- _addEntryNode(subNode,node); //添加子节点
- endResetModel();
- 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中:
parent(const QModelIndex &child) 用于返回一个节点的父节点索引:
- QModelIndex SqlMenuEntry::index(int row, int column, const QModelIndex &parent) const
- {
- if(!parent.isValid()) //parent为空,返回的是根节点的modelIndex,返回的同时,把节点数据指针(TreeNodePtr)保存在QModelIndex的internalPointer中,以便在其它函数中获取节点数据
- {
- if((row >= 0) && (row
- {
- return createIndex(row,column,mRootEntrys.at(row));
- }
- }else{
- TreeNodePtr parentNode = (TreeNodePtr)parent.internalPointer(); //返回子节点的modelIndex
- return createIndex(row,column,parentNode->childs[row]);
- }
- return QModelIndex();
- }
实现data(constQModelIndex&index,introle) 返回节点中的数据:
- 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());
- }
- 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{}
- }