Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

QVector<CustomClass> as a var property in QML. Qt 5.14 vs 5.12.



  • Hello Ladies and Gentlemen.

    Unsure if my idea would work, I created a DataPoint class marked with Q_GADGET with three properties defined using Q_PROPERTY. I placed Q_DECLARE_METATYPE(DataPoint) after the class definition. I also added qRegisterMetaType<DataPoint>() to the initialisation method of my main C++ class (let's call it MainClass).

    In my MainClass I defined a property:

    Q_PROPERTY(QVector<DataPoint> highPressureVector READ getHighPressureVector NOTIFY highPressureVectorChanged)
    

    I fill a corresponding MainClass member (that is used in the getter) m_highPressureVector with three DataPoint objects.

    In QML I use the forementioned property like this:

    property var points: mainObject ? mainObject.highPressureVector : []
    

    When I log its contents with:

    console.log("points = " + points + ", points.length = " + points.length)
    

    I get what I expect:

    qml: points = DataPoint(0, 1, red),DataPoint(1,2,red),DataPoint(2,3,red), points.length = 3
    

    The PROBLEM is that I did all this in Qt 5.14.2. I learned that we will use Qt 5.12.8. After compiling the exact same code with Qt 5.12.8 the line that prints points property looks like this:

    qml: points = QVariant(QVector<DataPoint>), points.length = undefined
    

    QUESTION: Is there a way to keep using QVector<DataPoint> as my property? Or do I have to make DataPoint inherit from QObject and use QVariantList or something like that?

    I also have a second less important question. Why does this happen? I haven't seen anything in the Qt 5.14 version description that would justify such a difference in behaviour.



  • It seems that I'm not the only one who has encountered this problem:
    https://stackoverflow.com/questions/58284209/how-to-pass-qvectorcustom-q-gadget-to-qml

    There is also a bug for that but it's still open even though QVector<GadgetClass> works in Qt 5.14.
    https://bugreports.qt.io/browse/QTBUG-73399

    It seems that someone changed something in 5.14 that is not well documented but has made a significant change in handling QVectors of gadgets.

    Since (for Qt 5.12) QML displays my points property as

    QVariant(QVector<DataPoint>)
    

    I assume that it is aware of the existence of DataPoint type. Why does it wrap it in QVariant in Qt 5.12? Is there a way to extract my vector from this variant so that QML treats it as an array?



  • OK, I gave up.

    Instead of using Q_GADGET I made DataPoint class inherit from QObject and added Q_OBJECT macro to it. Then I turned my property which stores DataPoints into a QList:

    Q_PROPERTY(QList<QObject*> highPressureList READ getHighPressureList NOTIFY highPressureListChanged)
    

    I wish I could have kept QVector<GadgetClass> though...

    I think that this is the change that is missing in 5.12 and is present in 5.14:
    https://bugreports.qt.io/browse/QTBUG-60338



  • Does it make any different to register QVector<DataPoint> as well:

    qRegisterMetaType<QVector<DataPoint>>()
    


  • I had some time to return to this problem and switch back DataPoint to Q_GADGET.

    @fcarney said in QVector<CustomClass> as a var property in QML. Qt 5.14 vs 5.12.:

    Does it make any different to register QVector<DataPoint> as well:

    qRegisterMetaType<QVector<DataPoint>>()
    

    Unfortunately it did not help. The vector in QML was visible as:

    QVariant(QVector<DataPoint>)
    


  • I found a satisfying solution. When my DataPoint class is a Q_GADGET and is registered as a metatype:

    Q_DECLARE_METATYPE(DataPoint);
    
    qRegisterMetaType<DataPoint>();
    

    it can be used in a QVariantList. The list is visible in QML as a JavaScript array. Then I can freely access all properties of each DataPoint in QML.

    Adding an object of my DataPoint class to a QVariantList exposed to QML looks like this:

    list.append(QVariant::fromValue(DataPoint{x, y, color}));
    

    Reading a single DataPoint object from the QVariantList looks for example like this:

    DataPoint lastdp = list.last().value<DataPoint>();
    

Log in to reply