class TreeModel : public QAbstractItemModel
{
Q_OBJECT
enum 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 roleNames() const;
private:
TreeItem *m_rootItem;
};
TreeItem.h头文件如下:
#ifndef TREEITEM_H
#define TREEITEM_H
#include
#include
#include
#include
class TreeItem
{
public:
TreeItem::TreeItem();
TreeItem(const QList &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 m_childItems;
QList m_itemData;
};
#endif
可以看出TreeModel是继承自QAbstractItemModel,其中QVariant data(const QModelIndex &index, int role) const;成员函数和QHashTreeModel::TreeModel(QObject *parent) :
QAbstractItemModel(parent), m_rootItem(NULL)
{
m_rootItem = new TreeItem;
QList list;
list.append("ZhongGuo");
list.append("ZhG");
auto item = new TreeItem(list, m_rootItem);
m_rootItem->appendChild(item);
QList BJ_List;
BJ_List.append("BeiJing");
BJ_List.append("BJ");
auto BJ_Item = new TreeItem(BJ_List, item);
item->appendChild(BJ_Item);
QList ShX_List;
ShX_List.append("ShannXi");
ShX_List.append("ShX");
QList XiAn_List;
XiAn_List.append("XiAn");
XiAn_List.append("XA");
QList 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 GuangDong_List;
GuangDong_List.append("GuangDong");
GuangDong_List.append("GD");
QList 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 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(parent.internalPointer())->columnCount();
}
else
{
return m_rootItem->columnCount();
}
}
QHash TreeModel::roleNames() const
{
QHash 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(index.internalPointer())->data(0);
}
case SIMPLIFY:
{
return static_cast(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(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(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(parent.internalPointer());
}
return parentItem->childCount();
}
以上即为TreeModel的源文件。
#include "TreeItem.h"
TreeItem::TreeItem() :m_parentItem(NULL)
{
}
TreeItem::TreeItem(const QList &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(this));
}
以上成员函数中,有一个比较特殊的函数:int TreeModel::columnCount(const QModelIndex &parent) const;因为在创建根目录时用的是无参构造m_rootItem = new TreeItem;所以QAbstractItemModel在调用hasChildren(const QModelIndex& parent)计算根的列数时,返回了0,导致TreeView控件会认为表是空表,所以不获取数据,最终显示出来是空的,调用堆栈如下图:
因此,在这里用无参构造根节点时,可以手动设置返回的列数(例如本例中返回2)。
import QtQuick 2.4
import QtQuick.Layouts 1.2
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
Rectangle {
id: root
property var ctrl
property var model
x:100
y:50
width: 800
height: 600
TreeView {
id:view
width: 500
TableViewColumn {
title: "Name"
role: "name"
width: 150
}
TableViewColumn {
title: "Simplify"
role: "simplify"
width: 200
}
model: root.model
itemDelegate: Item {
Text {
anchors.verticalCenter: parent.verticalCenter
color: "red"
elide: styleData.elideMode
text: styleData.value
}
}
property bool isCollapse: true
onClicked: {
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)在
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 _DEBUG
m_view.setSource(QUrl("qrc:/ui/TreeViewTest.qml"));
#else
m_view.setSource(QUrl("ui/TreeViewTest.qml"));
#endif
m_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】