[Development] [Interest] [Qt3D] Mixing C++ and QML

Sean Harmer sean.harmer at kdab.com
Fri Oct 20 12:33:27 CEST 2017


On 19/10/2017 19:44, Shawn Rutledge wrote:
> (thread started on the interest list, but I don’t think my comments
> belong there)
> On Oct 19, 2017, at 18:06, Sean Harmer <sean.harmer at kdab.com> wrote:
>> Hi,
>> you've hit one of the issues we did with exposing C++ and QML APIs.
>> Namely, QQmlListProperty. This thing should ideally never have
>> existed and instead support for properties of collections should
>> have been added to QObject and the metaobject system.
> What exactly do you think should be done there, in case we can fix it
> some day?

Probably something like how NSObject manages properties of collections. 
So far with Qt3D we've only needed the same level of semantics as 
offered by QQmlListProperty - or rather we've worked within those 
constraints. So a simple indexed container with the ability to 
add/remove items.

In a more general setting I can easily also imagine support for 
associative containers too.

The tricky part will be deciding which semantics do we wish to support 
and where do we draw the line between such properties and recommending 
to use a full-blown model instead.

Speaking of which, improving QAIM to be able to return data for 
contiguous blocks of indices in one function call would be a really 
welcome addition. Calling so many virtuals to retrieve a single data 
value for a single index and role is not exactly efficient. The existing 
QAIM API is fine for the existing views but doesn't scale well when 
trying to use them to populate, say a buffer of per instance data on a 
large scale. Yes I know we could avoid this with custom API but users 
have so many models at this point it would be nice to offer some 
interoperability with them.

> QObjects are normally managed as a tree for memory management
> purposes, so I’ve also long disliked the fact that it doesn’t quite
> match the nesting of the Item declarations in QML, because of the
> separate QList<QQuickItem *> childItems.  It’s confusing and wastes
> memory.

We avoided that in Qt 3D and just use the regular parent-child 
relationship. We don't have separation between visual parent and QObject 

> QQmlListProperty is flexible about storage, since you get to write
> all the accessors, so you can maybe use it just for QML and also have
> normal C++ API?

That's what we did. The C++ API has addComponent(), removeComponent(), 
componentCount() type functions, and then we have libraries sat on top 
for each aspect that add in the QQmlListProperty handling via extension 
objects. For e.g.


> A typical pattern in QtQuick is that a QQmlListProperty is the
> default property, so declared children are automatically added.  But
> instead you have to declare the Components first, and then also add
> them to a vector.  Why is that?  It seems needlessly cumbersome to
> me.  If Components are naturally always children of Entities,

^ that is your broken assumption. Components do not have to be children 
of the entity. We actually started out with that but found that it 
prohibits sharing components which can sometimes be handy.

then it
> ought to be enough to declare them inside an Entity.  But it seems
> that any QNode can have any number of QNode children, so maybe you
> could have a QQmlListPropery<QNode> as the default property, whose
> implementation uses the QObject children, just for convenience in
> QML?

Also whilst I'm here, there's an annoying limitation in the QML language 
that prevents mixing inline declaration of elements with elements 
referenced by id in a list property. That is you cannot write something 

Mesh { id: mesh }
Material { id: material }

Entity {
     components: [ Transform {}, material, mesh ]

> If you think there’s something wrong with the normal QObject
> parent/child relationship, then there’s another mechanism for
> detecting declared QML “children" and doing “something special” with
> them.

Do you mean the autoparent callback?


We need this here because it's not enough for us to know that the parent 
is a QObject. We need to know if it's a QNode to be able to add the new 
child to the scene.

One possible future solution we discussed with Lars and Simon for this 
is to make QObjectPrivate::setParent() virtual.

   We use it to make each Window transient for whatever Window or
> Item’s window that it was declared inside of, for adding
> PointerHandlers to Items, and stuff like that: any case where one
> object can be declared inside another, but it’s not quite a
> conventional parent/child relationship, for example because the
> “parent” and “child” aren’t the same kind of objects.
> Either of those mechanisms can keep the syntax nice in QML.
>> To avoid pulling in a QtQml dependency in the C++ API, we instead
>> have another layer to add the QML specifics (pretty much entirely
>> list properties).
> Ugh that would indeed be nice to simplify.
>> In order to create these from code we have a factory. Try something
>> like:
>> QAbstractNodeFactory::createNode<QEntity>("QEntity")
>> If using just C++ you will get a standard QEntity. If using QML
>> (and the types are registered with the factory) you will get the
>> QML -enhanced version with the extension object that handles the
>> list properties.
> If we had collection properties in QObject somehow, would you get rid
> of the factories?   Or everything is stuck in place now because of
> having public API?

I don't know if we could get rid of the factories yet, I've not thought 
it through sufficiently yet. However, if QObject properties could handle 
collections, we could certainly get rid of all the extension object 
boiler plate in the quick3dFoo libraries:


which in itself would be a very nice saving.



Dr Sean Harmer | sean.harmer at kdab.com | Managing Director UK
KDAB (UK) Ltd, a KDAB Group company
Tel. +44 (0)1625 809908; Sweden (HQ) +46-563-540090
Mobile: +44 (0)7545 140604
KDAB - Qt Experts

More information about the Development mailing list