Нет собственной модели QML, которая могла бы использовать TreeView, поэтому я реализовал модель, которая пытается быть универсальной:
TreeElement
// treeelement.h
#ifndef TreeElement_H
#define TreeElement_H
#include <QObject>
#include <QQmlListProperty>
class TreeElement : public QObject
{
Q_OBJECT
public:
Q_PROPERTY(QQmlListProperty<TreeElement> items READ items)
Q_CLASSINFO("DefaultProperty", "items")
TreeElement(QObject *parent = Q_NULLPTR);
Q_INVOKABLE TreeElement *parentItem() const;
bool insertItem(TreeElement *item, int pos = -1);
QQmlListProperty<TreeElement> items();
TreeElement *child(int index) const;
void clear();
Q_INVOKABLE int pos() const;
Q_INVOKABLE int count() const;
private:
static void appendElement(QQmlListProperty<TreeElement> *property, TreeElement *value);
static int countElement(QQmlListProperty<TreeElement> *property);
static void clearElement(QQmlListProperty<TreeElement> *property);
static TreeElement *atElement(QQmlListProperty<TreeElement> *property, int index);
QList<TreeElement *> m_childs;
TreeElement *m_parent;
};
#endif // TreeElement_H
// treeelement.cpp
#include "treeelement.h"
TreeElement::TreeElement(QObject *parent) :
QObject(parent),
m_parent(nullptr) {}
TreeElement *TreeElement::parentItem() const{
return m_parent;
}
QQmlListProperty<TreeElement> TreeElement::items(){
return QQmlListProperty<TreeElement> (this,
this,
&TreeElement::appendElement,
&TreeElement::countElement,
&TreeElement::atElement,
&TreeElement::clearElement);
}
TreeElement *TreeElement::child(int index) const{
if(index < 0 || index >= m_childs.length())
return nullptr;
return m_childs.at(index);
}
void TreeElement::clear(){
qDeleteAll(m_childs);
m_childs.clear();
}
bool TreeElement::insertItem(TreeElement *item, int pos){
if(pos > m_childs.count())
return false;
if(pos < 0)
pos = m_childs.count();
item->m_parent = this;
item->setParent(this);
m_childs.insert(pos, item);
return true;
}
int TreeElement::pos() const{
TreeElement *parent = parentItem();
if(parent)
return parent->m_childs.indexOf(const_cast<TreeElement *>(this));
return 0;
}
int TreeElement::count() const{
return m_childs.size();
}
void TreeElement::appendElement(QQmlListProperty<TreeElement> *property, TreeElement *value){
TreeElement *parent = qobject_cast<TreeElement *>(property->object);
parent->insertItem(value);
}
int TreeElement::countElement(QQmlListProperty<TreeElement> *property){
TreeElement *parent = qobject_cast<TreeElement *>(property->object);
return parent->count();
}
void TreeElement::clearElement(QQmlListProperty<TreeElement> *property){
TreeElement *parent = qobject_cast<TreeElement *>(property->object);
parent->clear();
}
TreeElement *TreeElement::atElement(QQmlListProperty<TreeElement> *property, int index){
TreeElement *parent = qobject_cast<TreeElement *>(property->object);
if(index < 0 || index >= parent->count())
return nullptr;
return parent->child(index);
}
TreeModel
// treemodel.h
#ifndef TreeModel_H
#define TreeModel_H
#include <QAbstractItemModel>
#include <QQmlListProperty>
class TreeElement;
class TreeModel : public QAbstractItemModel
{
Q_OBJECT
public:
Q_PROPERTY(QQmlListProperty<TreeElement> items READ items)
Q_PROPERTY(QVariantList roles READ roles WRITE setRoles NOTIFY rolesChanged)
Q_CLASSINFO("DefaultProperty", "items")
TreeModel(QObject *parent = Q_NULLPTR);
~TreeModel() override;
QHash<int, QByteArray> roleNames() const Q_DECL_OVERRIDE;
QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE;
Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE;
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
QModelIndex parent(const QModelIndex &index) const Q_DECL_OVERRIDE;
int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
QQmlListProperty<TreeElement> items();
QVariantList roles() const;
void setRoles(const QVariantList &roles);
Q_INVOKABLE QModelIndex indexFromElement(TreeElement *item);
Q_INVOKABLE bool insertElement(TreeElement *item, const QModelIndex &parent = QModelIndex(), int pos = -1);
TreeElement *elementFromIndex(const QModelIndex &index) const;
private:
TreeElement *m_root;
QHash<int, QByteArray> m_roles;
signals:
void rolesChanged();
};
#endif // TreeModel_H
// treemodel.cpp
#include "treemodel.h"
#include "treeelement.h"
TreeModel::TreeModel(QObject *parent) :
QAbstractItemModel(parent){
m_root = new TreeElement;
}
TreeModel::~TreeModel(){
delete m_root;
}
QHash<int, QByteArray> TreeModel::roleNames() const{
return m_roles;
}
QVariant TreeModel::data(const QModelIndex &index, int role) const{
if (!index.isValid())
return QVariant();
TreeElement *item = static_cast<TreeElement*>(index.internalPointer());
QByteArray roleName = m_roles[role];
QVariant name = item->property(roleName.data());
return name;
}
Qt::ItemFlags TreeModel::flags(const QModelIndex &index) const{
if (!index.isValid())
return nullptr;
return QAbstractItemModel::flags(index);
}
QModelIndex TreeModel::index(int row, int column, const QModelIndex &parent) const{
if (!hasIndex(row, column, parent))
return QModelIndex();
TreeElement *parentItem = elementFromIndex(parent);
TreeElement *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();
TreeElement *childItem = static_cast<TreeElement*>(index.internalPointer());
TreeElement *parentItem = static_cast<TreeElement *>(childItem->parentItem());
if (parentItem == m_root)
return QModelIndex();
return createIndex(parentItem->pos(), 0, parentItem);
}
int TreeModel::rowCount(const QModelIndex &parent) const{
if (parent.column() > 0)
return 0;
TreeElement *parentItem = elementFromIndex(parent);
return parentItem->count();
}
int TreeModel::columnCount(const QModelIndex &parent) const{
Q_UNUSED(parent)
return 1;
}
QQmlListProperty<TreeElement> TreeModel::items(){
return m_root->items();
}
QVariantList TreeModel::roles() const{
QVariantList list;
QHashIterator<int, QByteArray> i(m_roles);
while (i.hasNext()) {
i.next();
list.append(i.value());
}
return list;
}
void TreeModel::setRoles(const QVariantList &roles){
static int nextRole = Qt::UserRole + 1;
for(QVariant role : roles) {
m_roles.insert(nextRole, role.toByteArray());
nextRole ++;
}
emit rolesChanged();
}
QModelIndex TreeModel::indexFromElement(TreeElement *item){
QVector<int> positions;
QModelIndex result;
if(item) {
do{
int pos = item->pos();
positions.append(pos);
item = item->parentItem();
} while(item != nullptr);
for (int i = positions.size() - 2; i >= 0 ; i--)
result = index(positions[i], 0, result);
}
return result;
}
bool TreeModel::insertElement(TreeElement *item, const QModelIndex &parent, int pos){
TreeElement *parentElement = elementFromIndex(parent);
if(pos >= parentElement->count())
return false;
if(pos < 0)
pos = parentElement->count();
beginInsertRows(parent, pos, pos);
bool retValue = parentElement->insertItem(item, pos);
endInsertRows();
return retValue;
}
TreeElement *TreeModel::elementFromIndex(const QModelIndex &index) const{
if(index.isValid())
return static_cast<TreeElement *>(index.internalPointer());
return m_root;
}
main.cpp
#include "treemodel.h"
#include "treeelement.h"
#include <QGuiApplication>
#include <QQmlApplicationEngine>
static void registertypes(){
qmlRegisterType<TreeElement>("foo", 1, 0, "TreeElement");
qmlRegisterType<TreeModel>("foo", 1, 0, "TreeModel");
}
Q_COREAPP_STARTUP_FUNCTION(registertypes)
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
const QUrl url(QStringLiteral("qrc:/main.qml"));
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&app, [url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
}, Qt::QueuedConnection);
engine.load(url);
return app.exec();
}
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 1.4
import foo 1.0
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
TreeModel {
id: treemodel
roles: ["phrase"]
TreeElement{
property string phrase: "Hey"
TreeElement{
property string phrase: "What's"
TreeElement{
property string phrase: "Up?"
}
}
}
}
TreeView {
anchors.fill: parent
model: treemodel
TableViewColumn {
title: "Name"
role: "phrase"
width: 200
}
}
}
Выход:
Полный пример вы найдете здесь