[Solved] New TreeView does not connect to C++ model.
-
Hello guys, I was waiting long time before Qt 5.5 has been released because of new
TreeView
component.
I am trying in agony to make it work with my model in C++ for a week.
So, I am completely stuck in understanding how all this "kitchen" works.//main.qml import QtQuick 2.4 import QtQuick.Controls 1.4 import QtQuick.Window 2.2 import dataModel 1.0 ApplicationWindow { title: qsTr("Hello World") width: 640 height: 480 visible: true menuBar: MenuBar { Menu { title: qsTr("&File") MenuItem { text: qsTr("&Open") onTriggered: messageDialog.show(qsTr("Open action triggered")); } MenuItem { text: qsTr("E&xit") onTriggered: Qt.quit(); } } } TreeView { anchors.fill: parent model: DataModel TableViewColumn { title: "Name" role: "DisplayRole" width: 300 } } }
//main.cpp #include <QApplication> #include <QQmlApplicationEngine> #include <QtGui> #include <QtQml> #include "treemodel.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); QQmlApplicationEngine engine; qmlRegisterType<TreeModel>("dataModel", 1, 0, "DataModel"); engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); return app.exec(); }
//task.h #ifndef TASK_H #define TASK_H #include <QList> #include <QVariant> class Task { public: explicit Task(const QString &data, Task *parent = 0); ~Task(); void appendChild(Task *child); Task *child(int row) const {return m_childItems.value(row);} int childCount() const; int columnCount() const {return 1;} QVariant data(int column) const; int row() const; QString getName() const {return name;} Task *parentItem(); private: QList<Task*> m_childItems; //QList<QVariant> m_itemData; Task *m_parentItem; QString name;//data element for a while }; #endif // TASK_H
//task.cpp #include "task.h" #include <QVariant> #include <QDebug> Task::Task(const QString &data, Task *parent) { m_parentItem = parent; name = data;//to be modified } //Task::Task(QObject *parent) : QObject(parent) //{ // m_parentItem = parent; //} Task::~Task() { } void Task::appendChild(Task *child) { m_childItems.append(child); qDebug() << "appending a child";//it does not event shows } int Task::childCount() const { return m_childItems.count(); } int Task::row() const { if (m_parentItem) return m_parentItem->m_childItems.indexOf(const_cast<Task*>(this)); return -1; } Task *Task::parentItem() { return m_parentItem; }
//treemodel.h #ifndef TREEMODEL_H #define TREEMODEL_H #include <QAbstractItemModel> #include "task.h" class TreeModel : public QAbstractItemModel { public: //TreeModel(); explicit TreeModel(QObject *parent = 0); QModelIndex index(int row, int column, const QModelIndex & parent = QModelIndex()) const Q_DECL_OVERRIDE; QModelIndex parent(const QModelIndex &index) const Q_DECL_OVERRIDE; ~TreeModel(); int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE; //void setupModelData(Task *parent); /*enum RoleNames { TaskNameRole = Qt::UserRole, TaskDateCreatedRole = Qt::UserRole + 1, TaskParentsRole = Qt::UserRole+2, TaskChildrensRole = Qt::UserRole+3, BrightnessRole = Qt::UserRole+4 };*/ private: QList<Task> m_data; Task * rootItem; //QHash<int, QByteArray> m_roleNames; }; #endif // TREEMODEL_H
//treemodel.cpp #include "treemodel.h" #include "task.h" TreeModel::TreeModel(QObject *parent) : QAbstractItemModel(parent) { rootItem = new Task(QString("default name")); // m_roleNames[TaskNameRole] = "name"; // m_roleNames[TaskDateCreatedRole] = "dateCreated"; // m_roleNames[TaskParentsRole] = "parents"; // m_roleNames[TaskChildrensRole] = "childrens"; // m_roleNames[BrightnessRole] = "brightness";//to be changed //setupModelData(rootItem); //t rootItem->appendChild(new Task("alala1", rootItem) ); } QModelIndex TreeModel::index(int row, int column, const QModelIndex &parent) const { if (!hasIndex(row, column, parent)) return QModelIndex(); Task *parentItem; if (!parent.isValid()) parentItem = rootItem; else parentItem = static_cast<Task*>(parent.internalPointer()); Task *childItem = parentItem->child(row); if (childItem) return createIndex(row, column, childItem); else return QModelIndex(); //Q_UNUSED(parent); //if (row >= pkts.count() || row < 0 || column >= 8) // return QModelIndex(); //QStringList *pkt = pkts[row]; //return createIndex(row, column, 0/*No Hierarchy yet*/); } QModelIndex TreeModel::parent(const QModelIndex &index) const { if (!index.isValid()) return QModelIndex(); Task *childItem = static_cast<Task*>(index.internalPointer()); Task *parentItem = childItem->parentItem(); if (parentItem == rootItem) return QModelIndex(); return createIndex(parentItem->row(), 0, parentItem);//0 because tree structure. Trees have only children in first column } int TreeModel::rowCount(const QModelIndex &parent) const { Task *parentItem; /*if (parent.column() > 0) return 0;*/ if (!parent.isValid()) parentItem = rootItem; else parentItem = static_cast<Task*>(parent.internalPointer()); return parentItem->childCount(); } int TreeModel::columnCount(const QModelIndex &parent) const { if (parent.isValid()) return static_cast<Task*>(parent.internalPointer())->columnCount(); else return rootItem->columnCount(); } QVariant TreeModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); if (role != Qt::DisplayRole) return QVariant(); Task *item = static_cast<Task*>(index.internalPointer()); return item->getName();//for a while } //void TreeModel::setupModelData(Task *parent) //{ //} TreeModel::~TreeModel() { delete rootItem; }
How to make
TreeView
to show what is inside my C++ model? Please correct me if you see some bullsh!t! -
Hi @Kofr,
I find 2 issues here:-
When using C++ models subclassed from item models always re-implement roleNames because that it how the C++ model comes to know which data to send to the QML.
-
You have registered the component using
qmlRegisterType
but not initialized it in QML. You will need to do this:
DataModel { id: myModel }
and then assign it
TreeView { anchors.fill: parent model: myModel }
OR
instead you can also set the model as a context property in main.cppTreeModel treemodel; engine.rootContext()->setContextProperty("myModel",treemodel); engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
-
-
@p3c0 thank you. How to know which role the Tree to show?
title: "Name" role: "DisplayRole" width: 300 }
does this mean that now our Tree shows Qt::DisplayRole ??
I am listing my
TreeModel::data()
function to show that it must return data with any role. However this function is never called (no debug messages).QVariant TreeModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { qDebug() << "data() - index is invalid";//it does not event shows return QVariant(); } //if (role != Qt::DisplayRole) // return QVariant(); Task *item = static_cast<Task*>(index.internalPointer()); qDebug() << "data() - Data is about to be returned";//it does not event shows return item->getName();//for a while }
-
@Kofr No. These roles are different and should match exactly with those in C++ model. This problem is all due to roles not found. Re-implement the
roleNames
as follows:QHash<int, QByteArray> TreeModel::roleNames() const { QHash<int, QByteArray> roles; roles[TypeRole] = "DisplayRole"; return roles; } //and define role names enum RoleNames { TypeRole = Qt::UserRole + 10, }; //and then in data() ofcourse use as if (role != TypeRole) return QVariant();
-
-
@Kofr I am stuck into a similar problem, Can you by any chance provide the working code where the TreeView(with parent-child relation) is editable too? Considering that this post was really long back, but it will be a huge help if the code (completed with the qml and C++ too) is provided! Thanks in advance!