Declare list<vector2d> in QML and pass it to a C++ function which appends to the list?
-
How to declare a QList<QVector2D> in QML, then pass as an argument to an INVOKABLE C++ function, which appends to the QList? Fails at run-time.
C++ pseudocode:
class TopoDataItem : public QObject { Q_OBJECT Q_INVOKABLE bool runTest(QList<QVector2D> *qprofile) }
main.qml declares a list<vector2d> then passes that to the C++ when a button is pressed:
// Declare bathymetry profile property list<vector2d> profile [...] Button { text: qsTr('run test') onPressed: {topoDataItem.runTest(profile)} }
The call to topoDataItem.runTest(profile) generates this error:
"Could not convert argument 0 at" "expression for onPressed@qrc:/main.qml:174" qrc:/main.qml:174: TypeError: Passing incompatible arguments to C++ functions from JavaScript is not allowed.
What am I doing wrong? How should TopoDataItem::runTest() be declared, and how should it be invoked from QML?
Thanks! -
@jeremy_k - thanks for that clarification.
I ended up defining runTest() as follows:INVOKABLE QList<QVector2D> TopoDataItem::runTest(void ) { QList<QVector2D> profile; // Add content to profile [...] return profile; }
The QML invokes the method as follows:
Button { text: qsTr('run test') onPressed: { var profile = topoDataItem.runTest(); // Do stuff with profile data [...] } }
This seems to work with my application, without need to register additional stuff with the metatype system.
-
Have you tried QList<QVector2D>, rather than a pointer to QList?
#include <QGuiApplication> #include <QQmlApplicationEngine> int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); QQmlApplicationEngine engine; QObject::connect( &engine, &QQmlApplicationEngine::objectCreated, [&engine](QObject *obj, const QUrl & url) { qDebug() << obj->property("s"); }); engine.loadData("import QtQuick; QtObject { property list<vector2d> s }"); return app.exec(); }
Output with Qt 6.5:
QVariant(QList<QVector2D>, QList())
-
@jeremy_k I change the function signature to:
bool TopoDataItem::runTest(QList<QVector2D> &qProfile)
Now when I invoke from QML I get this error:
Error: Unknown method parameter type: QList<QVector2D>&
If I make the function argument const like this:
bool TopoDataItem::runTest(const QList<QVector2D> &qProfile)
Now QML successfully calls the function - but I cannot append to the QList, since it is declared const. But runTest() needs to add content to the QList<QVector2D> profile argument. What am I missing here?
Thanks! -
@Tom-asso said in Declare list<vector2d> in QML and pass it to a C++ function which appends to the list?:
@jeremy_k I change the function signature to:
bool TopoDataItem::runTest(QList<QVector2D> &qProfile)
Now when I invoke from QML I get this error:
Error: Unknown method parameter type: QList<QVector2D>&
The bridge between QML and C++ uses the metatype system.
Background reading:
https://doc.qt.io/qt-6/qmetatype.html#Q_DECLARE_METATYPEin particular:
Some types are registered automatically and do not need this macro:
Pointers to classes derived from QObject QList<T>, QQueue<T>, QStack<T> or QSet<T> where T is a registered meta type QHash<T1, T2>, QMap<T1, T2> or std::pair<T1, T2> where T1 and T2 are registered meta types QPointer<T>, QSharedPointer<T>, QWeakPointer<T>, where T is a class that derives from QObject Enumerations registered with Q_ENUM or Q_FLAG Classes that have a Q_GADGET macro
Note that pointer and reference to QList of registered types is not in that list. I'm mildly surprised that a const reference works. QList is implicitly shared, making copy construction relatively cheap.
If I make the function argument const like this:
bool TopoDataItem::runTest(const QList<QVector2D> &qProfile)
Now QML successfully calls the function - but I cannot append to the QList, since it is declared const. But runTest() needs to add content to the QList<QVector2D> profile argument. What am I missing here?
Thanks!See above concerning the metatype system.
Additionally, consider the ownership of objects in the list. The minimal non-working example in the first post suggests that the non-QObject objects are created by QML/javascript. Removing them from C++ can be a problem. For QObject instances, there's QJSEngine::setObjectOwnership(). For QVector2D, I have no idea.
-
@jeremy_k - thanks for that clarification.
I ended up defining runTest() as follows:INVOKABLE QList<QVector2D> TopoDataItem::runTest(void ) { QList<QVector2D> profile; // Add content to profile [...] return profile; }
The QML invokes the method as follows:
Button { text: qsTr('run test') onPressed: { var profile = topoDataItem.runTest(); // Do stuff with profile data [...] } }
This seems to work with my application, without need to register additional stuff with the metatype system.
-
T Tom asso has marked this topic as solved