Search code examples
qtqmlqobject

Qt/QML: std::vector<int> handling


Edit: problem was with 5.6 only, which has a reduced set of supported "native" types according to https://doc.qt.io/qt-5.6/qtqml-cppintegration-data.html vs the latest version ...

According to this page: https://doc.qt.io/qt-5/qtqml-cppintegration-data.html, std::vector<int> is suppported by QML if registered with qRegisterMetaType() and exposed/accessed as a property. However, I cannot get this to work.

My class (which can be instantiated by QML, so this level works) has declarations like:

// prop decl
Q_PROPERTY(std::vector<int> myVector READ myVector NOTIFY myVectorChanged)
// read accessor
Q_INVOKABLE std::vector<int> recordTime() const;
// signal (in signal section)
void myVectorChanged();

Registration via

qRegisterMetaType<std::vector<int> >("std::vector<int>");

When I push something into the vector and try accessing myVector.length or myVector.size, it returns 'undefined' (size() is not callable). How do I iterate over the elements? The page linked above says "Certain C++ sequence types are supported transparently in QML to behave like JavaScript Array types" (and mentions std::vector<int> in the list), so I expected length and index access to work.


Solution

  • The documentation says this container will be converted to a JS array automatically. You don't need to register anything.

    Of course, the conversion will be a copy, so modifying it will not modify the original array, and the way you use that is the same way you use a regular JS array. It definitely should have a length (not length()) property and support index access via [].

    Update:

    After your stories of failure I decided to actually run a simple test:

    class Test : public QObject {
        Q_OBJECT
      public slots:
        std::vector<int> test() { return std::vector<int> {1, 2, 3, 4, 5, 6, 7}; }
    };
    
    // in main.cpp
    qmlRegisterType<Test>("Core", 1, 0, "Test"); 
    
      // in qml
      Test {
        Component.onCompleted: {
          var t = test()
          console.log(t.length, t) // qml: 7 [1,2,3,4,5,6,7]
        }
      }
    

    As you can see, it gives the expected output, no need to register anything whatsoever.

    IIRC there was a problem with Qt that for some reason caused those automatic conversions to not kick in when you use a Q_PROPERTY interface. I suppose that issue is still valid, the solution thankfully is to simply not use a property but a simple return value.

    If your problems persist, I suggest to carefully examine your code, or if necessary, clean and rebuild your project, because the conversion is definitely working out as expected, aside from the property related issue.