[Interest] Guide me through the Qt offerings for GUIs

André Pönitz apoenitz at t-online.de
Sun Apr 25 22:12:52 CEST 2021

On Sun, Apr 25, 2021 at 06:41:17PM +0200, Ulf Hermann wrote:
> > 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
>     // 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;
> };

This Q_GADGET / QML_ANONYMOUS / Q_PROPERTY and whatever moc makes out of
it is one part of the glue code I mentioned that is not _necessary_ in the
widget case [Sure, I can use Q_PROPERTY also for classes that I use in
a widget context. In some cases this even can be helpful, e.g. if I
truly need introspection at runtime. On the other hand I practically never
need that, so it's not _necessary_ to have for the bulk of that code of
an application]

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

This restriction is imposed by peculiar choices of the QML language itself,
not a necessary consequence that one e.g. wants _some_ "declarative" way
to describe a part of a problem or _some_ hardware accelerated painting.

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

And these wrappers classes are another part of the glue code that is
_necessary_ for a C++-backend / QML frontend, but not for widgets.

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

Code size contributes to code complexity. Requirements to follow certain
patterns (which actually seem to change every now and then in this particular
context) contribute to code complexity. Patterns that require parts of the
code to repeat itself (e.g. the 'oneThing' name above) adds fragility.
Things get worse if violations of the rules are not detectable at compile
time or by static analysis anymore. Etc.

Anyway - this part of the discussion started with a claim that "the glue code
to make things work is a big pain" - for Widgets(!) and I stated that this
does not match what I see. To me it looks like your (appreciated...)
explanations on how to handle enums and QDir by wrapping them into custom
type pretty much confirms what I have said: QML needs glue code
that is not necessary in the QWidget case, not the other way round.

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

You know that I do appreciate your work to make QML easier to use. However,
I am still not convinced that a custom language (especially one that does
not fit _that_ seamlessly to C++) is needed at all.


More information about the Interest mailing list