0

I have a QList where each element is a instance of a c++ class. These instances contain information and based on that I want to create and move rectangles in QML. The contained information is the x position (among other things) and I want to create/move one rectangle per element in the QList. The QList gets updated in periodic intervals in runtime, meaning some elements can get added, removed or the x position edited.

I programmed a small example to understand how to accomplish the bridge between c++ and QML, but I think my code will only work once as a initialization and not if I update the QList in runtime. Am I on the right track and if not, what do I have to change? Is it necessary to use QAbstractListModel like suggested in the answers to this question by Timmmm?

Here's my code:
class.h:

#ifndef CLASS_H
#define CLASS_H

#include <QQuickItem>

class RectangelClass : public QObject
{
private:
    Q_OBJECT
    Q_PROPERTY(int xPos READ xPos WRITE setXPos NOTIFY xPosChanged)
    int m_xPos;

public:
    RectangelClass () {}
    int xPos() const { return m_xPos; }

public slots:
    void setXPos(int arg)
    {
        if (m_xPos == arg)
            return;

        m_xPos = arg;
        emit xPosChanged(arg);
    }

signals:
    void xPosChanged(int arg);
};

class RectangelClassManager : public QObject
{
private:
    Q_OBJECT
    Q_PROPERTY(QList <QObject*> rectangelClassList READ rectangelClassList WRITE setRectangelClassList NOTIFY rectangelClassListChanged)
    QList <QObject*> m_rectangelClassList;

public:
    RectangelClassManager ()
    {
        QList <QObject*> localObjList;
        for (int i = 0; i < 5; i++)
        {
            RectangelClass *localObj = new RectangelClass();
            localObj->setXPos (i*100);
            localObjList.push_back(localObj);
        }

        setRectangelClassList (localObjList);

    }

    QList <QObject*> rectangelClassList () const { return m_rectangelClassList; }

public slots:
    void setRectangelClassList (QList <QObject*> arg)
    {
        if (m_rectangelClassList == arg)
            return;

        m_rectangelClassList = arg;
        emit rectangelClassListChanged(arg);
    }

signals:
    void rectangelClassListChanged (QList <QObject*> arg);
};

#endif // CLASS_H

main.cpp:

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "class.h"
#include <iostream>

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

    qmlRegisterType<RectangelClass>("cppclasses", 1, 0, "RectangelClass");
    qmlRegisterType<RectangelClassManager>("cppclasses", 1, 0, "RectangelClassManager");

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

    return app.exec();
}

main.qml:

import QtQuick 2.4
import QtQuick.Window 2.2
import cppclasses 1.0


Window {

    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    RectangelClassManager{
        id: rectangelClassManager
    }

    Rectangle{
        id: rect0
        x: rectangelClassManager.rectangelClassList[0].xPos
        y: 100
        width: 80
        height: 80
        color:"yellow"
        Text {
            id: textid0
            anchors.centerIn: parent
            text: "X-Position: " + rectangelClassManager.rectangelClassList[0].xPos
        }
    }

    Rectangle{
        id: rect1
        x: rectangelClassManager.rectangelClassList[1].xPos
        y: 100
        width: 80
        height: 80
        color:"yellow"
        Text {
            id: textid1
            anchors.centerIn: parent
            text: "X-Position: " + rectangelClassManager.rectangelClassList[1].xPos
        }
    }

    Rectangle{
        id: rect2
        x: rectangelClassManager.rectangelClassList[2].xPos
        y: 100
        width: 80
        height: 80
        color:"yellow"
        Text {
            id: textid2
            anchors.centerIn: parent
            text: "X-Position: " + rectangelClassManager.rectangelClassList[2].xPos
        }
    }

    Rectangle{
        id: rect3
        x: rectangelClassManager.rectangelClassList[3].xPos
        y: 100
        width: 80
        height: 80
        color:"yellow"
        Text {
            id: textid3
            anchors.centerIn: parent
            text: "X-Position: " + rectangelClassManager.rectangelClassList[3].xPos
        }
    }

    Rectangle{
        id: rect4
        x: rectangelClassManager.rectangelClassList[4].xPos
        y: 100
        width: 80
        height: 80
        color:"yellow"
        Text {
            id: textid4
            anchors.centerIn: parent
            text: "X-Position: " + rectangelClassManager.rectangelClassList[4].xPos
        }
    }
}

Edit to make my question more clear:
Is it possible to update the QList in runtime in c++, will it be updated in QML and if not, how do I achieve that instead.

Vipr0
  • 59
  • 7
  • 1
    I suggest editing this post. What is your specific problem? What are you having trouble with? Too much ambiguity in your question. – Geno C Jul 09 '20 at 17:07

1 Answers1

1

Yes a QList property can be updated in runtime by emitting the rectangelClassListChanged() signal. However, this can be very ineffecient, since the whole list is reparsed. So, depending on how often your QList changes, you might be better of changing it to a QAbstractListModel.

Also, you can change your code to use a Repeater, it hurts my programmer-eyes ;-) and it might actually be the cause of not updating runtime.

import QtQuick 2.4
import QtQuick.Window 2.2
import cppclasses 1.0


Window {

    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    RectangelClassManager{
        id: rectangelClassManager
    }

    Repeater {
        model: rectangelClassManager.rectangelClassList

        delegate: Rectangle {
            x: modelData.xPos
            y: 100
            width: 80
            height: 80
            color:"yellow"
            Text {
                id: textid0
                anchors.centerIn: parent
                text: "X-Position: " + modelData.xPos
            }
        }
    }
}
Amfasis
  • 3,932
  • 2
  • 18
  • 27
  • Thank you very much for the answer. I'll keep the inefficiency in mind and I used the Repeater instead. One thing I still do not understand is, how to update the `QList` in the `main.cpp` though. I can not call the `setRectangelClassList()` method without creating a object of the class, but if I do that, nothing changes in QML. I basically want something like this in the `main.cpp`: `Sleep(2000); setRectangelClassList(newObjList);` – Vipr0 Jul 10 '20 at 13:56
  • 1
    @Vipr0 please look on SO/Google/[Qt docs](https://doc.qt.io/qt-5/qqmlcontext.html) about setting properties on the rootContext (can't properly answer at the moment, using smartphone) – Amfasis Jul 10 '20 at 14:23