One thing I noticed contributing to this effect is that it is apparently
difficult to pass objects of "medium" complexity through the glue layer > 
Simple stuff like integers and strings are fine (enums already get
interesting...), really complex stuff like QAbstractItemModels can be fine,
but for "two strings, an enum and an optional QDir" you already have to make
up your mind whether this is more like "three strings and an int" or more
like "something that needs moc". This contributes to an effect that I
consider self-censorship when it comes to selecting appropriate data
structures for the backend: If I know I can only expose certain types to the
frontend, I am tempted to used these types in the backend, not necessarily
the ones best suited one for the task. If the only tool is a hammer, ...

There is a difference between value types and object types in QML and that difference is closely related to the difference between types you would pass as pointer vs types you would pass as value in C++. For all of this you do need moc. Basically, any QObject derived class is an object type, and any Q_GADGET is a value type. The choice between those is about as difficult as it is in C++.

You can use any Q_GADGET as value type in QML these days:

struct MyMediumSizeValueType
{
    Q_GADGET
    QML_ANONYMOUS

    // I'm not sure whether plain MEMBER actually works.
    // Maybe you need a WRITE (and that would be a bug in QML).
    Q_PROPERTY(QString oneThing MEMBER oneThing)
    Q_PROPERTY(QString secondThing MEMBER secondThing)
    Q_PROPERTY(QDir thirdThing MEMBER thirdThing)

    QString oneThing;
    QString secondThing;
    QDir thirdThing;
};

Enums in value types are not supported because of naming requirements. Enums need to be part of uppercase-named types, and only object types and namespaces are uppercase-named. However, you can either expose an existing Q_GADGET as namespace using QML_FOREIGN_NAMESPACE (potentially in addition to exposing the same struct as value type) or you can move the enum to a suitable place if you're designing the whole thing from scratch for QML.

Named value types are still somewhat black magic, but we'll get to that soon-ish. You can use QML_ANONYMOUS and the QML "var" type for now. You can also have a QML_ANONYMOUS type as Q_PROPERTY of a C++ class, under its C++ name.

QDir is problematic because it does not expose any of its members as Q_INVOKABLE or Q_PROPERTY, and it's not a Q_GADGET. Your best bet is creating a wrapper type that does all these things. In that wrapper type you can also encode the "optional" nature of it. A pre-defined value type for QDir would be a candidate for our new QtCore QML module.

So, yes, QML is designed to use the metatype system. If you want to pass data to QML, you have to declare the types. Once, you have done so, it can be very easy to pass data back and forth in a structured way. The type declarations can live in their own headers, and they can be purely declarative, such as the example given above. While such declarations add some lines of code, they do not add a lot of complexity.

Granted, we have promoted other, worse ways of connecting QML and C++ in the past. In particular context properties. And, despite my recent efforts to clean this up, there are still some holes in the type system. For example named value types or (civilized) construction of value types in QML. However, on the plus side, you do not need to call qmlRegisterFooBar and figure out all the parameters to that anymore.

best,
Ulf
_______________________________________________
Interest mailing list
Interest@qt-project.org
https://lists.qt-project.org/listinfo/interest

Reply via email to