Solved Issue passing QML object to C++ QVariantMap
-
Hi,
I'm getting an error when trying to pass a simple QML object to a C++ function as a QVariantMap.
My CPPClass has a member:
Q_INVOKABLE cppFunc(QVariantMap obj) {}
Over in QML I have a ListModel that has elements like:
{ foo: 1, bar: 2, baz: 3}
I want to pull items from the list model and pass them to
cppFunc
. Like this:var obj =listModel.get(0) cppClass.cppFunc(obj)
Unfortunately, this produces the following runtime error:
Passing incompatible arguments to C++ functions from JavaScript is dangerous and deprecated.
However, if I create a new object based on the
obj
from thelistModel
then it works:var obj =listModel.get(0) var copyOfObj = {foo: obj.foo, bar: obj.bar, baz: obj.baz} cppClass.cppFunc(copyOfObj)
According to the debugger
obj
andcopyOfObj
are both valid and exactly the same.Can anyone explain why it's necessary to make this copy of a listModel item before passing it to C++?
Using Qt 5.12.5.
Thanks!
-
Hi @Josh, and welcome!
I'm not sure what's causing this behaviour, but:
- What does
console.log(typeof obj)
andconsole.log(typeof copyOfObj)
show? - The code which produces that error message is at https://code.woboq.org/qt5/qtdeclarative/src/qml/jsruntime/qv4qobjectwrapper.cpp.html#_ZL10CallMethodRK18QQmlObjectOrGadgetiiiPiPN3QV415ExecutionEngineEPNS3_8CallDataEN11QMetaObject4CallE -- Did you also get a message, "Could not convert argument X at Y"?
- What does
-
@Josh
thats because ListModel returns aobject
type and not a JSON object. Which i assume results in aQJSValue
on the C++ side (can easily be checked by changing the signature to take a QVariant and output the passed parameter with qDebug for example)https://code.qt.io/cgit/qt/qtdeclarative.git/tree/src/qmlmodels/qqmllistmodel.cpp?h=dev#n2550
-
@Josh
i honestly dont know if it works but try:var obj = JSON.parse(JSON.stringify(model.get(0)))
-
@JKSH Yes, also prints "Could not convert argument 1 at".
Console.log(typeof obj) & console.log(copyOfObj) show both as "object"
qml: object qml: object
-
@raven-worx said in Issue passing QML object to C++ QVariantMap:
@Josh
thats because ListModel returns aobject
type and not a JSON object. Which i assume results in aQJSValue
on the C++ side (can easily be checked by changing the signature to take a QVariant and output the passed parameter with qDebug for example)https://code.qt.io/cgit/qt/qtdeclarative.git/tree/src/qmlmodels/qqmllistmodel.cpp?h=dev#n2550
The original obj and copyOfObj are both "object" to QML, according to debugger and typeof.
On the C++ side, copyOfObj gets successfully passed into the QVariantMap.
This does work, but it's still generating a copy.
JSON.parse(JSON.stringify(entry)
It seems like it should work without the copy. According to the docs:
The QML engine provides automatic type conversion between QVariantList and JavaScript arrays, and between QVariantMap and JavaScript objects.
and
Similarly, if a C++ type uses a QVariantList or QVariantMap type for a property type or method parameter, the value can be created as a JavaScript array or object in QML, and is automatically converted to a QVariantList or QVariantMap when it is passed to C++.
Am I reading this wrong?
Thanks for your help!
-
@Josh said in Issue passing QML object to C++ QVariantMap:
It seems like it should work without the copy. According to the docs:
The QML engine provides automatic type conversion between QVariantList and JavaScript arrays, and between QVariantMap and JavaScript objects.But the returned object is actually of the type QObject.
As i said, try the approach where you change the parameter to a QVariant and check its actual type.IMHO the docs might be a bit misleading and should read "...and between QVariantMap and JSON objects."
-
@raven-worx said in Issue passing QML object to C++ QVariantMap:
@Josh said in Issue passing QML object to C++ QVariantMap:
It seems like it should work without the copy. According to the docs:
The QML engine provides automatic type conversion between QVariantList and JavaScript arrays, and between QVariantMap and JavaScript objects.But the returned object is actually of the type QObject.
As i said, try the approach where you change the parameter to a QVariant and check its actual type.IMHO the docs might be a bit misleading and should read "...and between QVariantMap and JSON objects."
You are correct. When passed as a QVariant the original obj is a QObject*, the copy is a QJSValue.
So copying/converting to a QJSValue is the right way to do this?
Yes the docs on this issue are confusing.
Thanks for your help.
-
@Josh said in Issue passing QML object to C++ QVariantMap:
So copying/converting to a QJSValue is the right way to do this?
this or
JSON.parse(JSON.stringify(entry)
-
@raven-worx That works for me. Thanks for clarifying this issue for me.