[Interest] Guide me through the Qt offerings for GUIs

Ulf Hermann ulf.hermann at qt.io
Sun Apr 25 18:41:17 CEST 2021

> 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

     // 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.


More information about the Interest mailing list