c++qtqml

Reading a QList<QPoint> in QML


I have the following class definition:

class PlaneGridQML : public QObject
{
    Q_OBJECT
    ........
    Q_INVOKABLE QList<QPoint> getPlanesPoints() {
        return m_PlaneGrid.getPlanesPoints();
    ......
}

In main I am making it available to the QML engine

PlaneGridQML pgq(10, 10, 3, false);
engine.rootContext()->setContextProperty("PlaneGrid",&pgq);

Then inside a QML Component I would like to do the following:

Connections {
    target: PlaneGrid
    onPlanesPointsChanged: {
        var pointsArray = PlaneGrid.getPlanesPoints()
        console.log(pointsArray[0].x)
    }
}

I am getting an error "Unknown method return type: QList" and obviously I cannot read pointsArray and display its first member. According to the Qt documentation QPoint can be directly transferred as a JS type. On the other hand QPoint does not derive from QObject.

Can anyone explain how can I list the elements of the array ( the QPoints ) in the JS function?


Solution

  • Yes, a QPoint will be auto converted to QML, and even a QList of certain objects will get auto converted to QML, but just because QList<int> works and QPoint work, it is not necessary mean that QList<QPoint> will also work.

    This is the list of automatic types in a list that QML supports:

    QList<int>
    QList<qreal>
    QList<bool>
    QList<QString> and QStringList
    QList<QUrl>
    QVector<int>
    QVector<qreal>
    QVector<bool>
    

    As you see, QPoint is not one of them.

    Wrapping in a QObject would be a waste.

    But do not despair. I suggest you declare QList<QPoint> * as a meta type, then you can wrap that in a QVariant to pass it as a opaque pointer to QML. Then, in your PlaneGridQML or another, single QObject derived type, you implement an interface to get the size of the list and individual points at a given index.

    You basically implement a standalone accessor / manipulator for lists of points. And you are all set.

    I also strongly recommend that you use QVector instead of QList in this scenario.

    class PlaneGridQML : public QObject
    {
        Q_OBJECT
        ........
        Q_INVOKABLE QPoint get(int i) { return planesPoints[i]; }
        ...
    }
    ...
    console.log(PlaneGrid.get(0).x)
    

    If you only have one plane grid and one set of points, you don't even need to pass the opaque pointer to QML, you can just directly use the plane grid to get the size and individual elements via index. Easy peasy.