Reputation: 13711
When I write a new component for QML in C++, I use the macro:
Q_PROPERTY(type READ getter WRITE setter NOTIFY signal)
Here I might use different types, e.g. int
or QVariant
. I was wondering, if I have any benefit of not using QVariant
here.
Without QVariant, this would be a problem for QObject::property() and for database work, etc.
So - what happens if I read or write to a property on the QML side?
My guess is, that it calls:
QVariant QObject::property(const char *name) const
bool QObject::setProperty(const char *name, const QVariant &value)
which means, that my properties, neatly defined as int, dobule, QString, ...
returned by my getter will be wrapped as QVariant
to be transferred from C++ to QML - a process that would be unnecessary if I would have defined it as QVariant
from the beginning.
If I have a Component in QML it is very likely that I have bindings from one property to multiple other properties, so reading happens quite often. So it would be a good idea to have the type in Q_PROPERTY
QVariant, as otherwise I would wrap it tons of times.
On the C++-Side I might decide, whether it is read often. If so, I buffer the value in the original data type for access within C++ but create the QVariant
when ever the value changes, so for QML it is unnecessary to create it multiple times. - Or is this happening automatically? Does a QML Object has all it's property values buffered as QVariant?
Upvotes: 1
Views: 3426
Reputation: 13711
I performed some analysis and experiments on QML that lead me to this answer, which I deem very probable:
Experiment: Add a property property var test
to an object, and analyze its meta object in C++. What I found is:
The QMetaObject::property()
method always returns a QVariant
as described in the signature of this method, but the type of the QVariant
is always set to the type of the property. This means a property int someInt
results in a QVariant::int
while a property var someVar
results in a QVariant::QVariant
- which means at least here, we have to unpack the value twice. +1 for using the best fitting property type!
Experiment: Add breakpoints to the source file of QVariant
(QtCore/qvariant.h
) at the line containing inline QVariant(QVariant &&other) Q_DECL_NOTHROW : d(other.d)
and inline QVariant &operator=(QVariant &&other) Q_DECL_NOTHROW
, which I found likely to be called when I change the value of a QVariant
in QML.
In QML I added a Button
which incremented its x
position upon click.
As expected, when ever I clicked the Button, those two lines were called repeatedly. Unfortunately, I am missing the insight, which QVariant
s where changed, and whether one of them is indeed our property for the position. However I don't think that Qt will have tons of QVariant
s somewhere in the backend, so I deem it likely, that my assumption is true, and on the QML-side the properties are handled as QVariant.
Take home message: Though the properties in QML are handled as
QVariant
it is beneficial to declare the properties using a better fitting type, as otherwise the result is not aQVariant::int
but maybe aQVariant::QVariant::int
.
In my experiments I found no trace of QJSValues
flying around which I would not have been surprised to find instead of QVariant::QVariant
when having a property var ...
Upvotes: 0
Reputation: 2232
No, i think you don't. At least if you expose it to QML or use in any kind of subclasses from QAbstractListModel
( all values there returned by data function and return type is QVariant
)
I have just run my app throught debugger with breakpoints to see what happens with Q_PROPERTY
variables. Just added simple code snipped in MouseArray onClicked
function:
var p = ExContact.phone;
var e = ExContact.status;
phone is QString
and status is qint8
Going throught breakpoints shows:
string
number
Calls trace is complicated in view but I can see what the QVariant is used and QMetaType is used.
So it looks like any type exposed throught Q_PROPERTY becomes QVariant anyway..
Upvotes: 1