PDA

View Full Version : Returning QVector<qreal> from C++ to QML and back to C++ as QVariantList



HÃ¥kon Enger
16th March 2017, 09:17
The Qt documentation (http://doc.qt.io/qt-5/qtqml-cppintegration-data.html) states that "Certain C++ sequence types are supported transparently in QML as JavaScript Array types", such as QVector<qreal>. This seems to work as expected, in that I can create a Q_INVOKABLE method returning a QVector<qreal> and read the values in QML/Javascript. However, if I try to pass the returned array to another C++ method which takes a QVariantList argument, the list received by the method is empty. Am I doing something wrong here?

The example below shows a method returning a length 5 array and passing it to another method, and gives the output:

qml: values.length: 5
list.size(): 0
list.size(): 3

while I would expect the second line to show "list.size(): 5". (The last line is just to show that passing a native JS array works as expected.) What is going on here? I am using Qt 5.8 on Linux. Thank you for any help or insight.

test.h:


#include <QVariantList>
#include <QVector>

#include <iostream>

class Test : public QObject {
Q_OBJECT
public:
Test(QObject *parent = 0) : QObject(parent) {}
virtual ~Test() {}

Q_INVOKABLE QVector<qreal> getValues() const
{
return { 1,2,3,4,5 };
}

Q_INVOKABLE void setValues(const QVariantList& list)
{
std::cout << "list.size(): " << list.size() << std::endl;
}
};


main.qml:


import QtQuick 2.5
import QtQuick.Window 2.2

Window {
visible: true
width: 640
height: 480
title: "Hello World"

Component.onCompleted: {
var values = Test.getValues();
console.log("values.length: " + values.length)
Test.setValues(values);
Test.setValues([1,2,3]);
}
}


main.cpp:


#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "test.h"

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

QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("Test", new Test());
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

return app.exec();
}

anda_skoa
16th March 2017, 12:38
The type of "values" is likely still a QVector<qreal>, so your first call to setValues() calls it with an imcompatible type for the value.

Have you tried changing the signature of setValues() to take the same type that getValues() returns?

Cheers,
_

HÃ¥kon Enger
17th March 2017, 09:14
Thanks for the suggestion, you are correct that if the setValues function takes a QVector<qreal>, there is no problem. However in my case the setValues function (which is actually in another class than the getValues function in the real application) needs to be able to take generic arrays, not just qreals. Changing the signature to setValues(const QVariant& variant) solved the problem, I can convert to a QVariantList using variant.value<QVariantList>() (not variant.toList(), which gives an empty list again.) But really, should there not be an error of some kind if I call a function with the wrong argument type?


(Edited after I realized I had a Q_PROPERTY(QVariantList values WRITE setValues ...) which would "convert" the array into an empty list even though I used a QVariant argument in setValues...)