I was tasked to come up with a simple architecture for remote real time instantiation of arbitrary QML components. I’ve split my findings into 3 blog entries, each one covering a slightly different topic. Part 1 focuses on the software design pattern used to dynamically instantiate components. Part 2 shows how to layout these dynamic components by incorporating QML' s positioning and layout APIs. The last entry, consisting of Parts 3 and 4, addresses the anchors API and important safety aspects.
This is Part 2: Laying Out Components with Qt Quick and JSON
Now that we know how to instantiate trees of components, the next thing we should be able to do is lay them out on screen. If you've watched our Introduction to QML series, you'll know Qt provides 4 ways to place objects in QML:
- Using the point coordinate system, where we pass x and y coordinates.
- Using Item Positioners
- Using Qt Quick Layouts, which are like positioners but can also resize their items using attached properties
- Using anchors, which allows us to link the item's center, baseline, and edges, to anchors from other items.
For maximum flexibility, the factory design approach should support all four methods of component placement.
- 1. The coordinate system we get almost for free. To use it, we can assign the values for x and y from onItemChanged in the instantiator Loader, as seen in Part I:
- 2. & 3...Item Positioners and Qt Quick Layouts work in very similar ways. So, let's have a look at how to approach Qt Quick Layouts, which is the most sophisticated of the two. Let's remember how Qt Quick Layouts are commonly used in the first place: First, we import QtQuick.Layouts. Then, instantiate any of these Layout components: https://doc.qt.io/qt-6/qtquick-layouts-qmlmodule.html, and set dimensions to it, often by means of attached properties (https://doc.qt.io/qt-6/qml-qtquick-layouts-layout.html#attached-properties). For the outermost Layout in the QML stack, we might use one of the previous APIs to achieve this. Here's a simple example for how that looks:
Now, for the Layouts API to work in our factory, the recursion described in Part I must be in place.
In addition to that, we need to take into account a property of the Loader object component: Loader inherits from Item. The items loaded by the Loader component are actually children of Loader and, as a result, must be placed relative to the loader, not its parent. This means we shouldn't be setting Layout attached properties onto the instantiated components, but instead should set them on the Loader that is parent to our item, IDed as instantiator.
Here's an example of what the model could define. As you can see, I've replaced the dot used for attached properties with an underscore.
Here's what we will do, based on that model:
As you can see, the attached property is set on the instantiator which acts as a container, and the component item is then anchored to that container. I do not simply anchor all children to fill the parent Loader because different components have different default sizes, and the Loader is agnostic of its children's sizes.
Here's the implementation for the Button, Column, and ColumnLayout components. Feel free to modify the JSON from factoryModel to use Column instead of ColumnLayouts, or any componentizations that you implement yourself.
- 4. Anchors will be covered in the next entry. Some complications and security implications arise due to the fact that anchors can point to IDs, which is why I think they deserve their own separate article.
To summarize, we can dynamically attach attributes to our dynamically instantiated components to configure QML layouts. It's important to keep in mind that the Loader will hold our dynamic component as its children, so we must assign our dimensions to the Loader and have the child mimic its behavior, possibly by anchoring to it, but this could also be done the other way around.
In the next entry I'll be covering how to implement anchors and the security implications for which dynamically instantiating components from JSON might not be a good idea after all. Our previous entry is Recursive Instantiation with Qt Quick and JSON.
Reference
Trusted software excellence across embedded and desktop platforms
The KDAB Group is a globally recognized provider for software consulting, development and training, specializing in embedded devices and complex cross-platform desktop applications. In addition to being leading experts in Qt, C++ and 3D technologies for over two decades, KDAB provides deep expertise across the stack, including Linux, Rust and modern UI frameworks. With 100+ employees from 20 countries and offices in Sweden, Germany, USA, France and UK, we serve clients around the world.