A Look at QUiLoader and QFormBuilder
If you've used Qt to develop widget-based applications, you almost certainly used Qt Designer to lay out screens or dialogs and then used the Qt User Interface Compiler (uic) program to generate the C++ code for the user interfaces. You may not be aware of another approach supported by Qt: generating user interfaces dynamically at run time using the Qt Designer UI files.
In this blog post we'll look at how this is supported by the QUiLoader and QFormBuilder classes in Qt.
QUiLoader
The QUiLoader class allows you to dynamically load a Qt Designer user interface (ui) file and instantiate it. Note that the uic compiler program is not involved; it loads the XML-based ui file and instantiates it without the need for any C++ code generation or compilation.
The basic use case is to create a QUiLoader instance and then call its load() method, specifying a .ui file (which can be a true file or a Qt resource). Here is a simple example:
QUiLoader loader;
QFile file(":/myform.ui");
file.open(QFile::ReadOnly);
QWidget *myWidget = loader.load(&file, this);
file.close();
A First Example
A complete code example is included in the source code [1] for this blog. It loads a simple ui file and instantiates it, using little more than the code above. Here is a screen shot of it running:
A Second Example
Internally, the QUiLoader class uses the methods createAction(), createActionGroup(), createLayout(), and createWidget() to dynamically create actions, action groups, layouts and widgets at run time. For example, the method createWidget() takes the name of a class to be instantiated, its parent object, and an object name. A list of the available widgets can be obtained using the method availableWidgets().
For a second example, I wrote a small application that presents the available widgets in a combo box and allows you to create instances of them inside a frame. A screen shot is shown below:
You can select a widget type and then instantiate it using the Create button. I added support for dragging a widget using the middle mouse button so you can move them around. Clicking in the Info button will display the properties for the created widgets, using Qt's metaobject facility:
The complete project for this example is included in the download as demo2.
QFormBuilder
The QFormBuilder class is similar to QUiLoader and is typically used by custom components and applications that embed Qt Designer. It has a similar API to QUiLoader, and in fact the first example will work simply by changing QUiLoader to QFormBuilder, e.g.
// QFormBuilder version
QFormBuilder builder;
QFile file(":/myform.ui");
file.open(QFile::ReadOnly);
QWidget *myWidget = builder.load(&file, this);
file.close();
It is derived from a base class called QAbstractFormBuilder, which you can subclass to create your own custom type of form builder. You also need to add "designer" to the Qt modules variable in your qmake project file to get it to successfully link, i.e.
Qt += core gui designer
An interesting capability of this class is that it also allows you to save a widget as a ui file. This is done with the save() method. A complete example of QFormBuilder that loads a form and then saves it is included as demo3 in the download for this blog post.
Conclusions
At ICS we have used the facilities described here to develop applications that provide GUI builder capability similar to Qt Designer within an application. You can imagine an application that could offer an interactive GUI builder that was designed for non-programmers, allowing them to lay out and modify screens. Keep these classes in mind if you have a similar requirement in your applications.
References
- Link to downloadable example code source, https://www.ics.com/sites/default/files/zip/uiloader.zip
- QUiLoader API documentation, http://doc.qt.io/qt-5/quiloader.html
- QAbstractFormBuilder API documentation, http://doc.qt.io/qt-5/qabstractformbuilder.html
- QFormBuilder API documentation, http://doc.qt.io/qt-5/qformbuilder.html