在Qt5.5之前是没有树控件的,我们在使用时用的是ListView来构造出一个树,Qt5.5之后的QML开发阶段,有了树控件TreeView,本篇着重记录QML的TreeView的使用。根据MVC分解文件(类)如下:
TreeController.h TreeController.cpp
TreeModel.h TreeModel.cpp
TreeItem.c TreeItem.cpp
各个类职能划分如下:
TreeController主要负责用户的操作,例如加载qml文件,用户主动加载数据,主动删除数据,主动插入数据等。TreeModel主要存放数据(TreeItem为TreeModel的成员,也是存放数据的)。QML的TreeView主要显示数据。
重点在于QML的TreeView与TreeModel如何交互将数据正确显示出来。

TreeModel.h头文件如下:

class TreeModel : public QAbstractItemModel
{Q_OBJECTenum ItemRoles {NAME = Qt::UserRole + 1,SIMPLIFY};
public:TreeModel(QObject *parent = NULL);~TreeModel();void appendChild(const QModelIndex& index);bool removeRows(int row, int count, QModelIndex parent);QModelIndex parent(const QModelIndex &index) const;Qt::ItemFlags flags(const QModelIndex &index) const;QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;int rowCount(const QModelIndex &parent = QModelIndex()) const;int columnCount(const QModelIndex &parent = QModelIndex()) const;QVariant data(const QModelIndex &index, int role) const;QHash<int, QByteArray> roleNames() const;private:TreeItem *m_rootItem;
};

TreeItem.h头文件如下:

#ifndef TREEITEM_H
#define TREEITEM_H  #include <QList>
#include <QVariant>
#include <QStringList>
#include <QModelIndex>class TreeItem
{
public:TreeItem::TreeItem();TreeItem(const QList<QVariant> &data, TreeItem* parent);~TreeItem();void appendChild(TreeItem *child);void deleteAllChild();TreeItem *child(int row);int childCount() const;int columnCount() const;QVariant data(int column) const;int row() const;TreeItem *parent();void setParent(TreeItem *parent);
private:TreeItem *m_parentItem;QList<TreeItem*> m_childItems;QList<QVariant> m_itemData;
};
#endif  

可以看出TreeModel是继承自QAbstractItemModel,其中QVariant data(const QModelIndex &index, int role) const;成员函数和QHash<int, QByteArray> roleNames() const;成员函数比较关键,是QML读取C++数据的关键函数。

TreeModel.cpp源文件如下:

TreeModel::TreeModel(QObject *parent) :
QAbstractItemModel(parent), m_rootItem(NULL)
{m_rootItem = new TreeItem;QList<QVariant> list;list.append("ZhongGuo");list.append("ZhG");auto item = new TreeItem(list, m_rootItem);m_rootItem->appendChild(item);QList<QVariant> BJ_List;BJ_List.append("BeiJing");BJ_List.append("BJ");auto BJ_Item = new TreeItem(BJ_List, item);item->appendChild(BJ_Item);QList<QVariant> ShX_List;ShX_List.append("ShannXi");ShX_List.append("ShX");QList<QVariant> XiAn_List;XiAn_List.append("XiAn");XiAn_List.append("XA");QList<QVariant> XiAn_GaoXin_List;XiAn_GaoXin_List.append("GaoXin");XiAn_GaoXin_List.append("XA_GaoXin");auto ShX_Item = new TreeItem(ShX_List, item);auto XA_Item = new TreeItem(XiAn_List, ShX_Item);auto XA_GX_Item = new TreeItem(XiAn_GaoXin_List, XA_Item);item->appendChild(ShX_Item);ShX_Item->appendChild(XA_Item);XA_Item->appendChild(XA_GX_Item);QList<QVariant> GuangDong_List;GuangDong_List.append("GuangDong");GuangDong_List.append("GD");QList<QVariant> DongGuan;DongGuan.append("DongGuan");DongGuan.append("DG");auto GuangDong_Item = new TreeItem(GuangDong_List, item);auto DongGuan_Item = new TreeItem(DongGuan, GuangDong_Item);item->appendChild(GuangDong_Item);GuangDong_Item->appendChild(DongGuan_Item);QList<QVariant> ShangHai;ShangHai.append("ShangHai");ShangHai.append("ShH");auto ShangHai_Item = new TreeItem(ShangHai, item);item->appendChild(ShangHai_Item);
}
TreeModel::~TreeModel()
{delete m_rootItem;
}
int TreeModel::columnCount(const QModelIndex &parent) const
{return 2;//返回实际的列数 (实际是他返回了0,因为根节点用的是无参的构造),TreeView控件会认为表是空表,不获取数据if (parent.isValid()){return static_cast<TreeItem*>(parent.internalPointer())->columnCount();}else{return m_rootItem->columnCount();}
}
QHash<int, QByteArray> TreeModel::roleNames() const
{QHash<int, QByteArray> names(QAbstractItemModel::roleNames());names[NAME] = "name";names[SIMPLIFY] = "simplify";return names;
}
QVariant TreeModel::data(const QModelIndex &index, int role) const
{if (!index.isValid()){return QVariant();}switch (role){case NAME:{return static_cast<TreeItem*>(index.internalPointer())->data(0);}case SIMPLIFY:{return static_cast<TreeItem*>(index.internalPointer())->data(1);}}
}
Qt::ItemFlags TreeModel::flags(const QModelIndex &index) const
{if (!index.isValid()){return 0;}return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
}
QModelIndex TreeModel::index(int row, int column, const QModelIndex &parent) const
{if (!hasIndex(row, column, parent)){return QModelIndex();}TreeItem *parentItem;if (!parent.isValid()){parentItem = m_rootItem;}else{parentItem = static_cast<TreeItem*>(parent.internalPointer());}TreeItem *childItem = parentItem->child(row);if (childItem){return createIndex(row, column, childItem);}else{return QModelIndex();}
}
QModelIndex TreeModel::parent(const QModelIndex &index) const
{if (!index.isValid()){return QModelIndex();}TreeItem *childItem = static_cast<TreeItem*>(index.internalPointer());TreeItem *parentItem = childItem->parent();if (parentItem == m_rootItem){return QModelIndex();}return createIndex(parentItem->row(), 0, parentItem);
}
int TreeModel::rowCount(const QModelIndex &parent) const
{TreeItem *parentItem;if (parent.column() > 0){return 0;}if (!parent.isValid()){parentItem = m_rootItem;}else{parentItem = static_cast<TreeItem*>(parent.internalPointer());}return parentItem->childCount();
}

以上即为TreeModel的源文件。
TreeItem.cpp源文件如下:

#include "TreeItem.h"
TreeItem::TreeItem() :m_parentItem(NULL)
{
}
TreeItem::TreeItem(const QList<QVariant> &data, TreeItem* parent) : m_parentItem(NULL)
{m_parentItem = parent;m_itemData = data;
}
TreeItem::~TreeItem()
{qDeleteAll(m_childItems);
}
void TreeItem::appendChild(TreeItem *item)
{item->setParent(this);m_childItems.append(item);
}
void TreeItem::deleteAllChild()
{for (int index = 0; index < m_childItems.size(); index++){m_childItems[index]->deleteAllChild();}qDeleteAll(m_childItems);m_childItems.clear();
}
TreeItem *TreeItem::child(int row)
{return m_childItems.value(row);
}
int TreeItem::childCount() const
{return m_childItems.count();
}
int TreeItem::columnCount() const
{return m_itemData.count();//return 1;
}
QVariant TreeItem::data(int column) const
{return m_itemData .value(column);
}
TreeItem *TreeItem::parent()
{return m_parentItem;
}
void TreeItem::setParent(TreeItem *parent)
{m_parentItem = parent;
}
int TreeItem::row() const
{if (!m_parentItem) { return 0; }return m_parentItem->m_childItems.indexOf(const_cast<TreeItem*>(this));
}

通过以上源文件可以看出,初始化的测试数据在TreeModel类的构造中传入。通过roleNames()函数增加QAbstractItemModel的角色,使得在QML中可以使用字段name和simplify,当QML加载读取数据时,通过枚举的角色NAME和SIMPLIFY返回对应的数据,即为要显示的数据,这样,就可以将C++的数据显示到QML的TreeView中了,以上其他的一些成员函数,都是一些获取数据个数的基本函数。

以上成员函数中,有一个比较特殊的函数:int TreeModel::columnCount(const QModelIndex &parent) const;因为在创建根目录时用的是无参构造m_rootItem = new TreeItem;所以QAbstractItemModel在调用hasChildren(const QModelIndex& parent)计算根的列数时,返回了0,导致TreeView控件会认为表是空表,所以不获取数据,最终显示出来是空的,调用堆栈如下图:

因此,在这里用无参构造根节点时,可以手动设置返回的列数(例如本例中返回2)。

加载TreeView的QML文件如下TreeViewTest.qml:

import QtQuick 2.4
import QtQuick.Layouts 1.2
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
Rectangle {id: rootproperty var ctrlproperty var modelx:100y:50width: 800height: 600TreeView {id:viewwidth: 500TableViewColumn {title: "Name"role: "name"width: 150}TableViewColumn {title: "Simplify"role: "simplify"width: 200}model: root.modelitemDelegate: Item {Text {anchors.verticalCenter: parent.verticalCentercolor: "red"elide: styleData.elideModetext: styleData.value}}property bool isCollapse: trueonClicked: {console.log("onClicked:", index)console.log("isExpanded:",isExpanded(index))if (isCollapse){console.log("expand")emit: view.expand(index);isCollapse = false;}else{console.log("collapse")emit: view.collapse(index);isCollapse = true;}/*if (isExpanded(index)){collapse(index);}else{expand(index);}*/}}
}

这里需要注意的是TreeView的bool isExpanded(QModelIndex index)在
clicked(QModelIndex index)中的应用,运行起来可以查看打的isExpanded:的值。值得注意的是,当点击根节点的三角进行展开收缩时,用isExpanded(QModelIndex index)函数获取的返回值跟实际的展开状态是反的,不点击三角进行收缩展开是正常的(由于在点击三角符号时,调用了一次原生的展开或收缩,然后又在clicked中调用了TreeView的expand(index);函数或发送emit: view.expand(index);信号,这会产生二次展开或收缩,负负得正,所以导致调用isExpanded(QModelIndex index)获取的值不理想,,,这可以算是QML的一个Bug吧),因此本例中用了成员变量property bool isCollapse: true进行变换以完成想要的功能。

加载QML界面的TreeController.cpp主要加载与数据暴露如下:

void TreeController::onBtnClicked()
{//m_view.setFlags(Qt::FramelessWindowHint | Qt::Window | Qt::WindowSystemMenuHint | Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint | Qt::WindowCloseButtonHint);if (m_isInit) {m_view.setTitle("LoadTest");m_view.rootContext()->setContextProperty("win", this);m_view.rootContext()->setContextProperty("quickView", &m_view);#ifndef _DEBUGm_view.setSource(QUrl("qrc:/ui/TreeViewTest.qml"));
#elsem_view.setSource(QUrl("ui/TreeViewTest.qml"));
#endifm_item = m_view.rootObject();QVariant v;v.setValue(this);m_item->setProperty("ctrl", v);QVariant v1;v1.setValue(&m_model);m_item->setProperty("model", v1);m_isInit = false;}m_view.show();
}

以上主要完成QML界面的加载和ctrl与model的暴露,其他窗口的操作(最小化最大化关闭)等操作函数在此忽略,有想了解更多技术的,可以扫描左侧栏二维码,关注本人公众号【三个程序员】,接收更实时有料的推送。

以上所有,完成了QML的TreeView加载数据并显示,展示了树控件TreeView的应用。

其效果如下图:

关于QML的TreeView使用得上篇到此结束,下篇主要写一些关于QML树控件TreeView的插入与删除操作,敬请期待!迫不及待想接收更多技术知识的朋友,可以扫描左侧二维码关注本人公众号,您的肯定与支持是我前进的动力^_^.

完整的demo程序工程地址如下:QML树控件TreeView的使用

【http://download.csdn.net/detail/shado_walker/9761108】

QML树控件TreeView的使用(上)相关推荐

  1. activex控件 新对象 ocx 初始化_Office已经支持64位的树控件Treeview了

    之前在使用Office365时发现微软其实已经悄悄地开始提供了64位的Treeview树控件,只是并没有公开宣布.当时是在一个网友的电脑上说他可以在64位Excel中可直接使用64位树控件,当时以为他 ...

  2. 【VBA】树控件TreeView的学习(二)

    哈喽,手机边亲爱的你还好吗?我是默默给大家分享Access知识的will. 上一篇文章我们简单讲了一下TreeView怎么 加载显示数据,TreeView上显示的数据都是手工添加的,那今天我们要来讲一 ...

  3. 【VBA】树控件TreeView的学习(一)

    哈喽,手机边亲爱的你还好吗?我是默默给大家分享Access知识的will. 大家2022年快乐,从今天开始我们来讲一下树控件. 树控件在我们的开发中是经常用的到的控件也是一个重点,我会从最简单的讲起, ...

  4. 【VBA树控件学习四】编辑与删除TreeView节点

    遇见春天 HI,我是默默等你来点赞的edon,大家最近忙吗? 今天,我们接着来讲一下TreeView树控件.之前,我们已经把新增节点的功能讲完了,接下来我们来讲一下编辑功能与删除功能. 这里我们只修改 ...

  5. QT中树控件QTreeView开发实例

    转自:http://mobile.51cto.com/symbian-268700.htm 本文讲解了QT中树控件QTreeView开发实例,对于QTreeView没有过多的讲解,那么不说废话了,看代 ...

  6. Bootstrap树控件(Tree控件组件)使用经验分享

    前言:很多时候我们在项目中需要用到树,有些树仅仅是展示层级关系,有些树是为了展示和编辑层级关系,还有些树是为了选中项然后其他地方调用选中项.不管怎么样,树控件都是很多项目里面不可或缺的组件之一.今天, ...

  7. SAP屏幕设计器专题:树控件的使用(九)

    在SAP的标准画面中,树控件都是随处可见,在一些特殊的应用中更有用处, 显得专业. 在SE51设计界面里,并没有直观的树控件,只是一个容器,要实现树功能还得在程序中用面向对象的方法实现. 本文就简要介 ...

  8. 树控件单击获取到的节点信息不是当前选中的节点_常用基本控件测试用例(一)...

    ​树控件的测试外观操作 1)项目中的所有树是否风格一致 2)树结构的默认状态是怎样的.比如默认树是否是展开,是展开几级? 是否有默认的焦点?默认值是什么?展开的节点图标和颜色? 3)验证点开节点时页面 ...

  9. [原创]FineUI秘密花园(二十四) — 树控件之数据绑定

    上一篇文章我们介绍了树控件的基本用法,不过都是通过标签来声明树控件的结构,本章我们会详细讲解如何在后台绑定树控件. 绑定到XmlDocument 下面通过一个简单的例子来看如何将XmlDocument ...

最新文章

  1. R语言nrow函数获取dataframe或者matrix行计数统计
  2. 识别、触达、转化、评估!百度云用ABC四招颠覆营销不可能
  3. javascript~callback回调函数
  4. 链式栈的实现(头文件及源程序)
  5. springboot2.5.5配置druid数据源1.2.8与jdbc
  6. 阿里研究院副院长:数字化是否可以买来?
  7. 基于JAVA+Servlet+JSP+MYSQL的在线购物系统
  8. cdn加载插件和npm安装的差别_web开发:打字机效果插件Typed.js
  9. bagging算法_Bagging与随机森林算法及其变种
  10. Android手机多种截图方式
  11. stylus 设置全局样式_vue 公共样式处理_全局styl文件
  12. CAD2019的使用
  13. leetcode.1024. 视频拼接
  14. 腾讯云点播html示例文件修改,实现视频居中效果
  15. dedecms 的采集
  16. TDMS转EXCEL
  17. fastapi身份认证
  18. MATLAB绘制实指数信号
  19. Lombok实现原理解析
  20. 飞机反推力液压装置半实物实时仿真系统

热门文章

  1. 显卡简介,显卡怎么查看
  2. SQL每日一题 牛客17 10月的新客户单价和获客成本
  3. 录屏,webm格式转gif的小技巧
  4. Android神兵利器之黄油刀的使用(ButterKnife)
  5. AWS两个VPC网络互通
  6. 使用 gfortran 编译 CALPUFF
  7. windows下,C++中调用命令行并且获取命令行的输出
  8. Gooxi国产化服务器专题介绍之海光服务器
  9. 校友小程序定制开发 带我们回到那个学生时代
  10. Java使用POI将doc文档转为Html