3

I'm currently in the situation, that I have a QList with MyClass also including a list QList.

To display this list-hierarchy I want to provide a Repeater within a ListView.

I tried this with a QStringList and it works fine (see uncommented lines below). When I try to do this with my QList I cannot access the name-property of MySubClass. Instead the name-property of MyClass is shown.

WRONG output:

Object 1
Object 1
Object 1
Object 2

Correct output should be:

Object 1
SubObject 1
SubObject 2
Object 2

EDIT: 08.12.2014 I found out, why the sublist did not work. I just had to replace one line in the delegate of the sub-ListView (name -> modelData.name).

Here's my code:

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QList>
#include <QDebug>

#include "myclass.h"

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    /* create simple stringlist */
    QStringList dataList;
    dataList << "Data 1"
         << "Data 2"
         << "Data 3";

    /* create more complex QObject List */
    MySubClass *mySubObject = NULL;
    QList<QObject *> mySubList;

    mySubObject = new MySubClass;
    mySubObject->setName("SubObject 1");
    mySubList.append(mySubObject);

    mySubObject = new MySubClass;
    mySubObject->setName("SubObject 2");
    mySubList.append(mySubObject);

    /* create object list */
    MyClass *myObject = NULL;
    QList<QObject *> myList;

    myObject = new MyClass;
    myObject->setName("Object 1");
    myObject->setDataList(dataList);
    myObject->setObjectList(mySubList);
    myList.append(myObject);

    myObject = new MyClass;
    myObject->setName("Object 2");
    myObject->setDataList(dataList);
    myList.append(myObject);

    qDebug () << myList.size();

    myObject = NULL;

    /* start engine and expose object list */
    QQmlApplicationEngine engine;

    QQmlContext *myContext = engine.rootContext();
    myContext->setContextProperty("myObjectList", QVariant::fromValue(myList));

    engine.load(QUrl(QStringLiteral("qrc:///main.qml")));

    return app.exec();
}

MyClass.h

#ifndef MYCLASS_H
#define MYCLASS_H

#include <QObject>
#include <QStringList>

#include "mysubclass.h"

class MyClass : public QObject
{
    Q_OBJECT
    Q_PROPERTY (QString name READ name WRITE setName NOTIFY nameChanged)
    Q_PROPERTY (QStringList dataList READ dataList WRITE setDataList NOTIFY dataListChanged)
    Q_PROPERTY (QList<QObject *> objectList READ objectList WRITE setObjectList NOTIFY objectListChanged)
public:
    inline MyClass(QObject *parent = 0) : QObject(parent) {}
    inline ~MyClass() {}

    QString name() const
    {
        return m_name;
    }

    QStringList dataList() const
    {
        return m_dataList;
    }

    QList<QObject *> objectList() const
    {
        return m_objectList;
    }

public slots:
    void setName(QString arg)
    {
        if (m_name != arg) {
            m_name = arg;
            emit nameChanged(arg);
        }
    }

    void setDataList(QStringList arg)
    {
        if (m_dataList != arg) {
            m_dataList = arg;
            emit dataListChanged(arg);
        }
    }

    void setObjectList(QList<QObject *> arg)
    {
        if (m_objectList != arg) {
            m_objectList = arg;
            emit objectListChanged(arg);
        }
    }

signals:
    void nameChanged(QString arg);
    void dataListChanged(QStringList arg);

    void objectListChanged(QList<QObject *> arg);

private:
    QString m_name;
    QStringList m_dataList;

    QList<QObject *> m_objectList;
};

#endif // MYCLASS_H

MySubClass.h

#ifndef MYSUBCLASS_H
#define MYSUBCLASS_H

#include <QObject>
#include <QString>

class MySubClass : public QObject
{
    Q_OBJECT
    Q_PROPERTY (QString name READ name WRITE setName NOTIFY nameChanged)

public:
    inline MySubClass(QObject *parent = 0) : QObject(parent) {}
    inline ~MySubClass() {}

    QString name() const
    {
        return m_name;
    }
public slots:
    void setName(QString arg)
    {
        if (m_name != arg) {
            m_name = arg;
            emit nameChanged(arg);
        }
    }
signals:
    void nameChanged(QString arg);

private:
    QString m_name;
};

#endif // MYSUBCLASS_H

main.qml

import QtQuick 2.2
import QtQuick.Window 2.1

Window {
    visible: true
    width: 360
    height: 360

    ListView  {
        id: view
        anchors.fill: parent

        model: myObjectList

        delegate: Item {
            width: parent.width
            height: col.height
            Column {
                id: col
                Text {
                    id: nameLabel
                    text: name
                }

                Repeater {
                    id: dataView
//                    model: dataList
                    model: objectList
                    delegate: Text {
                        id: dataLabel
//                        text: modelData
                        // text: name
                          /* Here's the fix!!! (dunno why, but it works) */
                          text: modelData.name
                    }
                }
            }
        }
    }
}
SGbo
  • 334
  • 6
  • 20
  • https://stackoverflow.com/questions/35160909/how-to-create-a-generic-object-model-for-use-in-qml – dtech Jul 03 '18 at 10:26

2 Answers2

5

For exposing to QML lists of QObject-derived types, one should use QQmlListProperty rather than QList<T> as the property type

MyClass.h:

Q_PROPERTY (QQmlListProperty<MySubClass> objectList READ getMySubClassList NOTIFY objectListChanged)

public:
   QQmlListProperty<MySubClass> getMySubClassList() {
      return QQmlListProperty<MySubClass>(this, 0, &MyClass::countMySubClassList, &MyClass::atMySubClassList);
   }
   static int countMySubClassList(QQmlListProperty<MySubClass> *property) {
      MyClass *m = qobject_cast<MyClass *>(property->object);
      return m->m_objectList.size();
   }
   static MySubClass *atMySubClassList(QQmlListProperty<MySubClass> *property, int index) {
      MyClass *m = qobject_cast<MyClass *>(property->object);
      return m->m_objectList[index];
   }
private:
   QList<MySubClass *> m_objectList

Also, you should register MySubClass type in the QML system, by using qmlRegisterUncreatableType

qmlRegisterUncreatableType<MySubClass,1>("project.mySubClass",1,0,"mySubClass","error message");
Meefte
  • 6,469
  • 1
  • 39
  • 42
  • Thanks, I implemented the QQmlListProperty and it seems to work. - This is the first time, that I use a QList instead a QAbstractListModel and for me it seems like QQmlListProperty is much more powerful than a QAbstractListModel. Can you explain that? – SGbo Dec 05 '14 at 14:09
  • @Quperman As model, QAbstractItemModel is much more powerful, simple and flexible solution. You can use QQmlListProperty as model, if you want to expose simple short const list. In other case QAbstractItemModel would be preferable. – Meefte Dec 06 '14 at 05:14
0

Try to add Q_DECLARE_METATYPE(MySubClass*) after class definition, in my case QList worked properly, ah, and I passed QObjectList as property

Melebius
  • 6,183
  • 4
  • 39
  • 52