Desktop styling with Qt Quick Controls

Qt Quick Controls 1 was our first UI framework for QML. The controls were mostly written in QML without much C++. At the time, QML was still a new technology, which meant that we didn’t have enough experience with designing for performance to know what to expect. So the styling API ended up inefficient by design, with many fat delegates that used extensive amounts of JavaScript, bindings, introspection, Loaders, and QObjects for both control logic and styling. It also had a linking dependency to Qt Widgets to get native styling and Widget-based dialogs. And without the QML compiler that we have today, this all ended up as a rather slow and messy approach. When we realized that it also didn’t perform well on embedded hardware, it was time to rethink the solution. And the result was Qt Quick Controls 2.

Qt Quick Controls 2

With Controls 2 the basic idea was to shift most of the implementation from QML to C++. By doing so, we aimed at slimming down the delegates as much as possible, and instead do the heavy lifting from C++. This included all the control logic, mouse, touch, event handling, API, and more. Only the visuals were left to be defined in QML. This resulted in thin delegates, less run-time overhead, less memory usage, clearer code flow, and faster execution.

But one thing that has been missing so far, is support for native desktop styling. The main motivation for Controls 2 was to achieve good performance on embedded devices, and since we had Qt Widgets for desktop, we sort of accepted that some essential desktop features were missing. We shipped styles that have open documentation (Universal, Material), and made it easy to create custom ones. But now that Controls 1 has been deprecated since Qt 5.12, and will also be excluded from the Qt 6 binary package, it’s time to work on desktop-oriented styles again.

Native desktop styles

In Qt 6.0, we are adding two new desktop styles to Controls 2: Windows and macOS. Unlike the existing Fusion style, which uses Qt Quick primitives, these new styles use QStyle for drawing. The reason is that it still does a good job of interfacing with “low-level” platform APIs to get true native styling. But instead of sharing QStyle with Widgets, we make an exclusive copy just for Controls. The latter might sound odd, since it’s natural to assume that sharing one codebase would be an easier approach. But the reasons are several: first of all, we don’t want to break Widgets or any 3rd party styles out there. And we cannot factor QStyle out of Widgets without breaking source compatibility. Not only does QStyle have references to Widgets all over its API, but it also uses enums and constants directly from the Widgets themselves. At the same time, we don’t want Controls to have a dependency on Widgets long into the future either.

Another reason is that we want the freedom to change the code wherever we see fit. There are many ways we can optimize the QStyle-copy going forward, to better fit the Qt Quick scene graph and the Controls styling API. One such change is that we only use QStyle for drawing the background of a control. The same background texture will be cached and reused for all controls of the same type, and scaled to the correct size with the help of a QSGNinePatchNode. The text and foreground will be rendered on top using normal QML. And for all such differences, we want to be able to implement them without being constrained or worried about keeping compatibility with Widgets. For the same reasons, the fact that we use QStyle for drawing is a private implementation detail. Controls already has a great styling API, and we don’t want to introduce and maintain a second one.

Lastly, we don’t necessarily want the native styles to look exactly like Widgets. For some controls, we use a hybrid approach, with QML to add animations and fading effects on top of the textures painted by QStyle. In the end, what we really want is for the native styles to have fluid performance, and to look as “native” as possible, and not necessarily like Widgets.

What is ready for Qt 6.0?

For Qt 6.0, most controls will be supported by the new desktop styles. But not all. Those that will be missing are the ones that currently don't have an implementation in QStyle from before, like Switch or RangeSlider. They are still available, but will be drawn with the Fusion style. Missing controls will gradually be supported in upcoming releases of Qt, the same with native dialogs and menus. And if we look even further, our plans include offering more desktop-centric controls that you might find in Widgets or native toolkits today.

So, still lots to do. But we see the new desktop styles as the first step of many to bring Controls on par with Widgets for desktop development over the next few years.

Below are screenshots of a Qt Quick Controls 2 application running with the new desktop styles. Note that this is still ongoing work, and any glitches will be ironed out before the final release.

 

macOS style (dark mode):



Windows style:

 

Fusion style (for comparison):


Blog Topics:

Comments

Commenting for this post has ended.

K
Kelteseth
4 points
53 months ago

Nice! But the windows style looks like 20 year old windows. Are there any plans for Microsoft Fluent Design?

Thorbjørn Lindeijer
0 points
53 months ago

Wouldn't the Universal style help you there? https://doc.qt.io/qt-6/qtquickcontrols2-universal.html Or is that significantly different from the Fluent design?

R
rossy
0 points
52 months ago

The Windows style is still what most Win32 desktop apps look like, including File Explorer, WordPad, Paint, some dialogs in Office, HTML forms in Firefox, and so on. This seems like Microsoft's fault by letting the desktop theming APIs stagnate, and not making it clear what a native desktop app should look like.

K
Kelteseth
0 points
52 months ago

None of the apps you described looks like this. Qt should go forward not backwards with features...

R
rossy
1 point
52 months ago

They absolutely do. Open a dialog in one of those programs and you'll see it, like the Properties dialog in File Explorer or the Paragraph dialog in WordPad.

J
Joe
2 points
53 months ago

Is it possible to do the same thing in Qt Widgets with C++? Applying styles with CSS is very slow, so there should be a way to create day/night mode faster in Qt with C++.

Flavio Tordini
1 point
53 months ago

Great job and very useful. What about an iOS style? That would be the last style really missing in Qt Quick Controls.

F
Felgo
1 point
53 months ago

You get iOS style with the Felgo controls: https://felgo.com/qt

K
Kelteseth
4 points
53 months ago

We now are at a clusterfuck where some Qt version have features, some are required to buy via marketplace, some are only fixed in Felgo, that is actually Qt but not so much.

ekke
-1 points
53 months ago

+1 for an iOS Style I'm using Controls 2 Material Style for my mobile business apps on Android / iOS / W10 (Touch) apps Even very complex apps are running with great performance and UX looking forward to Qt6 supporting strict QML/C++ integration later

N
Nils Jeisecke
1 point
53 months ago

Great to see some love for the desktop again!

Nikos Chantziaras
1 point
53 months ago

I believe KDE Framworks has a good solution for this, called "QQC2-Desktop-Style". It works with Qt 5. Note that it does NOT require KDE. It's an independent KF module:

https://api.kde.org/frameworks/qqc2-desktop-style/html/index.html

It makes QC2 looks like what you would get if you used Widgets instead, so it also works on Linux.

邓佳佳
1 point
53 months ago

Qt Quick Controls2 has met the needs of most scenarios through custom styles.We are using pure QML to make a complex PC client, which includes complex interactions between multiple windows. The main tasks are:

-We have made a lot of adaptations in scenarios with multiple monitors and different zoom ratios, such as the transfer of screen information between parent and child windows
-It is required to display some widgets outside the window drawing range, such as a label prompt outside a window. These are currently all implemented using sub-windows, which is very troublesome and difficult to manage
-The support for window transparency effects under the Windows 7 Basic theme is not good, so that our products cannot run in this environment at all

A
askjvxy vetrobfhpab
1 point
52 months ago

I must say that your first reason for not factoring QStyle out of widgets doesn't sound so good. The transition between major versions is a perfect opportunity to do backwards-incompatible changes.