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



Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.