欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  php教程

使用C++实现QML的TreeView Model (二)

程序员文章站 2022-04-20 15:18:42
...

使用C++实现QML的TreeView Model (二)

上文已经介绍过二维表模型的实现方式,接着分享层次模型的实现,首先实现一个节点类用于保存树状数据模型的节点数据和节点关系:

  1. class TreeNode;

  2. typedef TreeNode* TreeNodePtr;

  3. class TreeNode
  4. {
  5. public:
  6. explicit TreeNode();
  7. TreeNodePtr parent() const;
  8. void setParent(const TreeNodePtr p); //设置父节点,根节点的父节点为NULL
  9. void appendNode(TreeNodePtr node);
  10. void removeNode(int row);
  11. void setData(int role,QVariant value);
  12. QListchilds; //用于保存子节点指针,把childs放到public不好,仅仅是为了方便,不要学。

  13. private:
  14. TreeNodePtr mParent=NULL; //父节点
  15. QHashmRecord; //一个节点可以保存一行数据,哈希表的key是整型,用于保存role,QVariant保存数据

  16. };
TreeNode的实现也是相当简单:

  1. TreeNodePtr TreeNode::parent() const
  2. {
  3. return mParent;
  4. }

  5. void TreeNode::setParent(const TreeNodePtr p)
  6. {
  7. this->mParent = p;
  8. }

  9. void TreeNode::appendNode(TreeNodePtr node)
  10. {
  11. childs.append(node);
  12. }

  13. void TreeNode::removeNode(int row)
  14. {
  15. childs.removeAt(row);
  16. }


  17. QVariant TreeNode::data(int role)
  18. {
  19. return mRecord[role];
  20. }

  21. void TreeNode::setData(int role, QVariant value)
  22. {
  23. mRecord[role] = value;
  24. }
接下来开始对SqlMenuEntryModel进行手术:

  1. class SqlMenuEntry:public QAbstractItemModel,public QQmlParserStatus
  2. {
  3. Q_OBJECT
  4. public:
  5. explicit SqlMenuEntry(QObject *parent=0);
  6. ~SqlMenuEntry();
  7. enum MenuEntryRoles{idRole=Qt::UserRole+1,nameRole,defaultEntryRole,customEntryRole,iconRole,iconHoverRole};
  8. int rowCount(const QModelIndex &parent=QModelIndex()) const;
  9. int columnCount(const QModelIndex &parent=QModelIndex()) const;
  10. QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const;
  11. QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const;
  12. QModelIndex parent(const QModelIndex &child) const;
  13. QHashroleNames() const;
  14. private:
  15. QHash mRoleNames;
  16. QListQHashint,QVariant>> mRecords; //QList不能保存树状数据,干掉
  17. QList mRootEntrys; //用于保存根节点
  18. void _addEntryNode(TreeNodePtr node,TreeNodePtr parent=0); //用于向树添加节点
  19. };
_addEntryNode的实现如下:

  1. void SqlMenuEntry::_addEntryNode(TreeNodePtr node, TreeNodePtr parent)
  2. {
  3. if(parent == NULL)
  4. {
  5. mRootEntrys.append(node);
  6. }else{
  7. node->setParent(parent);
  8. parent->appendNode(node);
  9. }
  10. }

可以通过如下代码向模型添加数据:


  1. beginResetModel();

  2. auto node = new TreeNode();
  3. node->setData(nameRole,"parent 1");
  4. node->setData(iconRole,"parenticon1");
  5. _addEntryNode(node); //添加第一个根节点
  6. auto subNode = new TreeNode();
  7. subNode->setData(nameRole,"child1");
  8. _addEntryNode(subNode,node); //添加子节点

  9. endResetModel();
上面的代码向模型添加了一个根节点parent1和parent1的一个子节点child1,接下来可以对SqlMenuEntryModel进行持续改进,让TreeView可以顺利显示正确的数据和数据关系。首先,更改int rowCount(const QModelIndex &parent)让模型可以正确的返回根节点数和子节点行数:

  1. int SqlMenuEntry::rowCount(const QModelIndex &parent) const
  2. {
  3. if(parent.isValid()) //parent不为空,则要获取的行数是某个节点的子节点行数
  4. {
  5. TreeNodePtr parentNode = (TreeNodePtr)parent.internalPointer(); //节点信息在index时被保存在QModelIndex的internalPointer中
  6. return parentNode->childs.size();
  7. }
  8. return mRootEntrys.size(); //否则返回的是根节点行数

  9. }


实现index接口函数,让模型可以返回子节点的modelIndex同时将对应的节点指针保存在modelIndex的internalPointer中:

  1. QModelIndex SqlMenuEntry::index(int row, int column, const QModelIndex &parent) const
  2. {
  3. if(!parent.isValid()) //parent为空,返回的是根节点的modelIndex,返回的同时,把节点数据指针(TreeNodePtr)保存在QModelIndex的internalPointer中,以便在其它函数中获取节点数据
  4. {
  5. if((row >= 0) && (row
  6. {
  7. return createIndex(row,column,mRootEntrys.at(row));
  8. }
  9. }else{
  10. TreeNodePtr parentNode = (TreeNodePtr)parent.internalPointer(); //返回子节点的modelIndex
  11. return createIndex(row,column,parentNode->childs[row]);
  12. }
  13. return QModelIndex();
  14. }
parent(const QModelIndex &child) 用于返回一个节点的父节点索引:

  1. QModelIndex SqlMenuEntry::parent(const QModelIndex &child) const
  2. {
  3. TreeNodePtr node = (TreeNodePtr)child.internalPointer();
  4. if(node->parent() == NULL)
  5. {
  6. return QModelIndex(); //根节点没有parent
  7. }else{
  8. return createIndex(0,1,node->parent());
  9. }
实现data(constQModelIndex&index,introle) 返回节点中的数据:
  1. QVariant SqlMenuEntry::data(const QModelIndex &index, int role) const
  2. {
  3. TreeNodePtr node = (TreeNodePtr)index.internalPointer();
  4. return node->data(role);
  5. }

经过上面的打造,模型已经可以正常为TreeView提供数据:

  1. TreeView{
  2. anchors.fill: parent
  3. TableViewColumn {
  4. title: "Name"
  5. role: "name"
  6. }

  7. TableViewColumn {
  8. title: "Entry"
  9. role: "icon"
  10. }
  11. model:MenuEntryModel{}
  12. }
继续干活去了,明天再继续补充数据添加、删除和更新的相关经验。
相关标签: android