Declarative Widgets is a QML plugin that adds Qt Widgets support to QML. This means we can now easily mix the power of QML with the comfort of a Widgets UI on desktop.
Background
Declarative Widgets was born out of a breakfast discussion about how awesome it would be to use QML to describe QWidget-based scenes. If you have ever worked on a Qt Quick project and then switched back to creating a Widgets UI you will understand how frustrating it can be to write and maintain a complex UI in plain C++, or even create and modify UI files in Qt Designer.
The real power of QML, however, is in property bindings. Property bindings allow us to set the value of a property as an expression that is evaluated when ever a property involved in that expression changes. Take the following example:
The title
property of the GroupBox
is updated when the text
property of either LineEdit
changes. We could build this example in C++, but in QML we don't need to write any boilerplate code to connect to signals or define slots. By using Declarative Widgets we don't need to worry about writing our own UI components either; we can make use of all the existing widgets we developed warm, fuzzy feelings for over the years.
Implementation
To get an idea of how the Declarative Widgets plugin works, lets take a look at how QWidget
is integrated into QML.
QWidget
needs a few tweaks in order to integrate it into QML: there is no default property, the x
, y
, width
and height
properties are read-only, and the geometry
and visible
properties do not have notify signals. Rather than modifying QWidget
directly we can useqmlRegisterExtendedType
to register an extension object which adds or overrides the properties we need.
Our extension object, DeclarativeWidgetExtension
, derives from DeclarativeObjectExtension
which provides us with a default property. A default property is the property to which a value is assigned if an object is declared within another object's definition without declaring it as a value for a particular property. In Qt Quick, the default property is used to construct the visual scene hierarchy, and we do the same with Declarative Widgets to create the QWidget hierarchy, calling QWidget::setParent
, QWidget::setLayout
, or QWidget::addAction
depending on the type of the declared object. Note that we have to redeclare the data
property because qmlRegisterExtendedType
doesn't see the one from the base class.
To make the read-only properties writable, we override the existing property and provide a WRITE
accessor function to make the appropriate change. Let's take a look at the new x
property:
The READ
accessor function simply calls the original READ
accessor function on the extended type. However, QWidget
does not have an existing setX
function so we have to update the x
property using QWidget::setGeometry
.
Keen observers will notice that we haven't emitted any of the NOTIFY
signals that we declared. This is because widgets respond to events delivered to them by Qt as a result of things that have happened either within the application or as a result of outside activity that the application needs to know about. In order to hook into this system, our extension object installs itself as an event filter on the object we are extending. An event filter receives all the events for the target object before the target does, allowing us to observe and react to the events as required.
In our event filter we simply emit the NOTIFY
signals when we receive the appropriate event. In our x
property example we receive a QEvent::Move
event as a result of our call to QWidget::setGeometry
. This is where we emit posChanged
.
The geometry
and visible
properties that we overrode to add a NOTIFY
signal to simply call the original QWidget
READ
and WRITE
accessor functions. Then, in the event filter we emit the new signals when we receive the appropriate event.
What about QQuickWidget or QWebEngineView?
There are no additional limitations to using QQuickWidget
with Declarative Widgets. One of the use cases we came up with for using Declarative Widgets is as a stepping stone to porting existing Qt Widgets applications to Qt Quick. The first step of the port would be to isolate the business logic and replicate the existing UI using Declarative Widgets (we even wrote a tool to generate QML files from .ui files). You could then replace chunks of the UI with QtQuick components displayed in QQuickWidgets
.
To see QQuickWidget
or QWebEngineView
in action take a look through our examples on GitHub.
How do I get it?
The Declarative Widgets source code is available on GitHub: https://github.com/KDAB/DeclarativeWidgets
If you like Declarative Widgets please consider contributing to the project. Adding Qt Widgets support to QML is a large task and whilst we have done most of the ground work there are surely features we have missed. If there are features you need and you are unable to contribute, please get in touch and we will see what we can do about implementing them for you.
View our 'Widgets and more' video series
Yes, widgets are still alive and kicking. In the many years we have worked with them, we have gathered quite a number of tips and tricks that we’d love to share with you.
14 Comments
5 - Apr - 2018
Alexxey593
Great! This has to be in Qt itself!
6 - Apr - 2018
Alex
+1
6 - Apr - 2018
js
As soon as it's LGPL there can be more contributions...
9 - Apr - 2018
Kevin Krammer
An early version of that was featured in a talk at Qt Developers Days 2013: https://www.youtube.com/watch?v=NqpJEj15t9Q
And another time in a lightning talk at Qt Developer Days 2014: https://www.youtube.com/watch?v=wF24ahBNWi4
And in a talk at KDE Akademy 2014: https://conf.kde.org/en/Akademy2014/public/schedule/events/124.html
25 - Apr - 2018
Ernesto
Why Qt has not going done this path and they have created all the QQuickControl?
25 - Apr - 2018
Nathan Collins
Declarative Widgets allows you to use Qt Widgets with QML, but it does not use Qt Quick. Declarative Widgets is still using the Qt Widgets rendering and wrapping platform native components under the hood, whilst Qt Quick uses OpenGL for rendering (a software renderer is now available) and you had to build your UI from basic components. Qt Quick Controls provide standard controls for Qt Quick.
4 - Nov - 2020
Aleksey
License? :)
4 - Nov - 2020
Nathan Collins
Hi Aleksey,
the license details are included in the repository, but to save you a click Declarative Widgets is available under the terms of:
4 - Nov - 2020
Aleksey
Examples look strange me, not clear what they try to demonstrate? Why there is no example with DeclarativeObjectExtension? Can I use custom widget in QML?
18 - Jan - 2021
Nathan Collins
Hi Aleksy,
there are three example applications that show how to use the DeclarativeWidgets plugin in an application: bookstore, config-editor and text-editor. In addition the examples directory contains a number of QML files that can be run using the declarativewidgets binary the projects produces (runner target in Qt Creator). Pass the full path to one of those example files to declarativewidgets to see the result. I'm updating the read-me on GitHub with this information.
Regarding the use of your custom widgets and DeclarativeObjectExtension: if you take a look at src/declarativewidgets_plugin.cpp you can see how we use DeclarativeObjectExtension and derived classes to register the Qt widgets with QML. Notice that many of them work using the DeclarativeWidgetExtension as the extension type. Depending on your custom widget, you may also be able to use DeclarativeWidgetExtension to extend your own widget. Otherwise you might have to write your own extension object to expose anything that is missing.
27 - Aug - 2022
SC
It is mentioned that KDAB has "even wrote a tool to generate QML files from .ui files)".
Is the tool freely available or under license?
Thanks
31 - Aug - 2022
Nathan Collins
Hello, the tool is available as part of the Declarative Widgets repository, covered by the same license as the rest of the code: https://github.com/KDAB/DeclarativeWidgets/tree/master/ui2dw
23 - Oct - 2022
Faisal
Hi, we are looking to create our own QWidget and we’d like to use your plugin in order to use it inside a QML file.
Is that possible? if so, elaborate
Thank you
24 - Oct - 2022
Nathan Collins
Hi Faisal,
it sounds like you want to use a QWidget in an existing Qt Quick application. Declarative Widgets don't enable that - they allow you to describe a Qt Widgets application declaratively using QML, rather than imperatively in code. Declarative Widgets does not let you embed a QWidget inside a Qt Quick application.
I hope that helps, Nathan