Planned maintenance: From Sunday 8th December 10:00 CET there will be changes to try and solve the caching issues that have been experienced. If anyone has a problem connecting after this period then please PM @AndyS or any of the moderators.

[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!


  • Moderators

    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.cpp

    TreeModel 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
    }
    

  • Moderators

    @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();
    


  • @p3c0 Great success! Now it works.
    stage 1 is complete. Now running to make it editable.


  • Moderators

    @Kofr Nice. Happy Coding..



  • @Kofr @p3c0
    I need some help regarding re-ordering of the item of the QAbstractItemModel. I have put a MouseArea in the itemDelegate which allows me to drag an item. I need some help to call C++ function of the QAbstractItemModel to move items to support the dynamic re-ordering. Kindly advice



  • @Valerian I did not do d&d yet. In my idea you should register a signal to be emitted whenever you move mouse in the area of new position and call swap function.
    Do you feel something like this?