QML树控件TreeView的使用(上)
在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的使用(上)相关推荐
- activex控件 新对象 ocx 初始化_Office已经支持64位的树控件Treeview了
之前在使用Office365时发现微软其实已经悄悄地开始提供了64位的Treeview树控件,只是并没有公开宣布.当时是在一个网友的电脑上说他可以在64位Excel中可直接使用64位树控件,当时以为他 ...
- 【VBA】树控件TreeView的学习(二)
哈喽,手机边亲爱的你还好吗?我是默默给大家分享Access知识的will. 上一篇文章我们简单讲了一下TreeView怎么 加载显示数据,TreeView上显示的数据都是手工添加的,那今天我们要来讲一 ...
- 【VBA】树控件TreeView的学习(一)
哈喽,手机边亲爱的你还好吗?我是默默给大家分享Access知识的will. 大家2022年快乐,从今天开始我们来讲一下树控件. 树控件在我们的开发中是经常用的到的控件也是一个重点,我会从最简单的讲起, ...
- 【VBA树控件学习四】编辑与删除TreeView节点
遇见春天 HI,我是默默等你来点赞的edon,大家最近忙吗? 今天,我们接着来讲一下TreeView树控件.之前,我们已经把新增节点的功能讲完了,接下来我们来讲一下编辑功能与删除功能. 这里我们只修改 ...
- QT中树控件QTreeView开发实例
转自:http://mobile.51cto.com/symbian-268700.htm 本文讲解了QT中树控件QTreeView开发实例,对于QTreeView没有过多的讲解,那么不说废话了,看代 ...
- Bootstrap树控件(Tree控件组件)使用经验分享
前言:很多时候我们在项目中需要用到树,有些树仅仅是展示层级关系,有些树是为了展示和编辑层级关系,还有些树是为了选中项然后其他地方调用选中项.不管怎么样,树控件都是很多项目里面不可或缺的组件之一.今天, ...
- SAP屏幕设计器专题:树控件的使用(九)
在SAP的标准画面中,树控件都是随处可见,在一些特殊的应用中更有用处, 显得专业. 在SE51设计界面里,并没有直观的树控件,只是一个容器,要实现树功能还得在程序中用面向对象的方法实现. 本文就简要介 ...
- 树控件单击获取到的节点信息不是当前选中的节点_常用基本控件测试用例(一)...
树控件的测试外观操作 1)项目中的所有树是否风格一致 2)树结构的默认状态是怎样的.比如默认树是否是展开,是展开几级? 是否有默认的焦点?默认值是什么?展开的节点图标和颜色? 3)验证点开节点时页面 ...
- [原创]FineUI秘密花园(二十四) — 树控件之数据绑定
上一篇文章我们介绍了树控件的基本用法,不过都是通过标签来声明树控件的结构,本章我们会详细讲解如何在后台绑定树控件. 绑定到XmlDocument 下面通过一个简单的例子来看如何将XmlDocument ...
最新文章
- R语言nrow函数获取dataframe或者matrix行计数统计
- 识别、触达、转化、评估!百度云用ABC四招颠覆营销不可能
- javascript~callback回调函数
- 链式栈的实现(头文件及源程序)
- springboot2.5.5配置druid数据源1.2.8与jdbc
- 阿里研究院副院长:数字化是否可以买来?
- 基于JAVA+Servlet+JSP+MYSQL的在线购物系统
- cdn加载插件和npm安装的差别_web开发:打字机效果插件Typed.js
- bagging算法_Bagging与随机森林算法及其变种
- Android手机多种截图方式
- stylus 设置全局样式_vue 公共样式处理_全局styl文件
- CAD2019的使用
- leetcode.1024. 视频拼接
- 腾讯云点播html示例文件修改,实现视频居中效果
- dedecms 的采集
- TDMS转EXCEL
- fastapi身份认证
- MATLAB绘制实指数信号
- Lombok实现原理解析
- 飞机反推力液压装置半实物实时仿真系统