[Interest] QQmlPropertyList x QList in hybrid C++/QML APIs

Sandro Andrade sandroandrade at kde.org
Fri Jun 14 21:43:12 CEST 2013

On Fri, Jun 14, 2013 at 3:59 PM, Alan Alpert <416365416c at gmail.com> wrote:
> On Fri, Jun 14, 2013 at 11:49 AM, Sandro Andrade <sandroandrade at kde.org> wrote:
>> On Fri, Jun 14, 2013 at 2:48 PM, Alan Alpert <416365416c at gmail.com> wrote:
>>> To use types across QML/C++ you should use qmlRegisterType.
>>> QObject-based types aren't automatically registered with QML, but
>>> certain things may still work. element.ownedAttributes is undefined
>>> because you haven't registered the type.
>> Ok, I've confirm that, but it seems that properties with type QList<T *>
>> still are handled as QVariant(QList<T *>), even if T is registered in QML.
>> It works only if property type is QVariantList, is that right ?
> If you register both T and the class the property is on to QML, then
> you should be able to use QList<T*> property as a read-only list of T.
> QQmlListProperty is only strictly necessary when the list can be
> modified from QML.

No success yet :) ... I have no need so far to handle those item as UML objects,
like UmlClass { ownedOperations: [UmlOperation {}] }. I just need to access
them via javascript at Component.onCompleted function.

I've qml-registered all my custom types (ex: qmlRegisterType<QUmlClass>();)
and I've set context property by running:

_quickView->engine()->rootContext()->setContextProperty("element", umlClass);

in Component.onCompleted:
console.log("element.ownedAttributes:" + typeof
element.ownedAttributes + ", " + element.ownedAttributes);

element.ownedAttributes:object, QVariant(QList<QUmlProperty*>)

while if doing:

QVariantList varList;
foreach(QUmlProperty *property, umlClass->ownedAttributes())
    varList << qVariantFromValue(property);
_quickView->engine()->rootContext()->setContextProperty("properties", varList);

javascript output now shows:

properties: object, QUmlProperty(0x1105970,
"name"),QUmlProperty(0x110f2e0, "age")
and it's handled as a javascript array, as expected.

Am I missing something ?

>>> However you don't have to maintain two different classes. You can just
>>> register the same C++ class into QML. To interact with the list
>>> property properly (mostly just assigning to it in QML, i.e. UmlClass {
>>> ownedOperations: [UmlOperation {}] } ) you need to have a
>>> QQmlListProperty type property, not just the QList<QObject*> property.
>>> But the QQmlListProperty type is basically just a wrapper around a
>>> QList<QObject*> (providing better control of the allocation if you
>>> need it), so it will be using the same QList<QObject*> as the data.
>>> You just need the extra property, not duplicating or synchronizing
>>> data, so it's easy to put it on the same C++ class and there's very
>>> little more you have do to use it properly in QML.
>> Ok, but that requires a new property name to prevent name clashing,
>> doesn't it ? I'd have to have something like:
>> Q_PROPERTY(QList<QUmlProperty *> ownedAttributes READ ownedAttributes)
>> and
>> Q_PROPERTY(QQmlListProperty<QUmlProperty *> qmlOwnedAttributes READ
>> ownedAttributes)
> Yes. But this usually isn't a problem for one of the following reasons
> A) You only access the property as a property from QML, so the
> QQmlListProperty is the only property needed (the ownedAttributes
> method still returns the QList for the C++ API, and the
> qmlOwnedAttributes method for the QQmlListProperty isn't used from
> C++).

Actually I need both, since I'm using a QtWidgets-based generic property
editor to manipulate such properties. I could port this editor to QML, but
iirc we are still lacking a treeview quick control ...

> B) You almost always access the property from QML as a default
> property, like the children property in QQuickItem. Then the second
> name doesn't matter because it's never explicitly typed.

Awesome, that's actually great :)

> Option A) is recommended for a cleaner QML API anyways. If you want a
> clean QML API and use the properties heavily from C++, then you do run
> into this problem where the best workaround is a separate QML
> (sub)class.

Ok, that seems to be my case.

Thanks ...

> --
> Alan Alpert

More information about the Interest mailing list