Wiki

The Evolution of Qt Designer

by Trenton Schulz
Qt Designer supplied with Qt 4.0 comprises many features that makes it the fastest and easiest way to lay out and design forms. In this article, we'll take a look at the history of Qt Designer and some of the new features and design decisions in Qt 4.0.

Early GUI Builders

The Qt API has always made it easy to create a form. Using layout managers, we can create forms relatively quickly. Still, this approach can rapidly become tedious if you have many forms to create. There's also the "edit, compile, run" cycle as you check the positioning of widgets. During all of this you may start to think that there really should be a GUI for making your GUI.

Already with Qt 1, there were a few GUI builders available as open source software, with varying levels of layout and widget support.

  • Qt Architect, developed by Jeff Harris and Klaus Ebner, allowed you to lay out the widgets, edit pixmaps for icons, and edit code for the forms. It was probably the most commonly used GUI builder for versions 1 and 2 of Qt.
  • QtEZ, created by Sam Magnuson and later maintained by Jan Prokop, allowed you to develop most of your application without leaving the program. It could even generate a main() function for you.
  • Ebuilder, by Ernie van der Meer, focused on the parent--child relationships of widgets and on building these hierarchies.
Still, our users kept asking for a tool that was supported by Trolltech and that would always be synchronized with Qt releases. Also, early versions of these tools only offered manual placement for child widgets, a major obstacle to cross-platform development.

The First Designer

Trolltech released Qt Designer 1.0 at the same time as Qt 2.2. From day one, dialogs created in Qt Designer were stored in well-structured XML files (.ui files) that a separate tool, the User Interface Compiler (uic), converted into C++ code. Qt applications could also create forms based on .ui files at run-time, using the QWidgetFactory class.

Qt Designer 1.0 also had the ability to define signals and slots and to connect them together. The actual implementation of the slots was done by subclassing the uic-generated classes and reimplementing the slots, which were declared virtual by uic. The diagram below summarizes the situation.

The first version of Qt Designer also provided full support for horizontal, vertical, and grid layouts. Qt developers could rapidly add child widgets to a form, snap them into a layout, and see how they would behave when the user resized the dialog. This immediate feedback cut out the "edit, compile, run" cycle of laying out widgets.

It wasn't all rosy, though. Support for custom widgets was very limited; they were rendered as a static image in the form, making it hard to tell how the actual form would behave without building it. Additionally, the subclassing technique was somewhat cumbersome (as the diagram above illustrates) and required two classes, both with the Q_OBJECT macro, resulting in needless overhead on Qt/Embedded. Finally, Qt Designer 1.0 didn't support the creation of main windows with menus and toolbars.

The Second Designer

Qt Designer 2.0 was released with Qt 3.0. It offered many features that set it apart from the original Qt Designer. First, it allowed developers to cut subclassing by using the .ui.h mechanism. The .ui.h file was included by the uic-generated source and allowed you to reimplement slots and even deal with construction and destruction of the form.

A code editor was included inside of Qt Designer to edit the .ui.h file. Furthermore, there was a Source tab that allowed you to add member variables, includes, and forward declarations, in addition to signals and slots.

The second Qt Designer could also load several types of plugin. Widget plugins allowed you to create a plugin of your custom widget, making it possible to see the widget when using it on a form and access its properties. Another use of plugins was for wizards. It was even possible to connect to databases from inside Qt Designer and view their data.

In addition, Qt Designer 2.0 included a .pro file parser, enabling you to manage your project from Qt Designer and to use the built-in code editor to edit your source files. Some users developed entire applications using Qt Designer.

Making a Better Designer for Qt 4

Qt Designer was now an integral part of Qt, but there were still things that could be done to make it better. For instance, the code editor missed such features as being able to go to a specified line. There were also synchronization issues if you were editing a .ui.h file outside Qt Designer.

Another issue with Qt Designer was that it couldn't be integrated into existing IDEs. This meant that developers who enjoyed the productivity of IDEs had to leave it to use Qt Designer. Also, adding signals, slots, data members, declaration and implementation includes, and more inside the Source tab was usually considered more troublesome than just editing the source files directly.

All this and more lead to the work that would be part of the next Qt Designer. Many concepts needed to be revisited. As a result, an early glimpse of Qt Designer was part of the first Qt 4 beta. A second version containing a more complete feature set was introduced in beta 2 of Qt 4. The version contained in Qt 4's Release Candidate should be almost identical to that in the final Qt 4 release. Let's take a look at some of the features that are part of the new Qt Designer.

Better Integration with Existing IDEs

Qt Designer has now been fully compartmentalized to make it possible to integrate it with existing IDEs. This means that you can create a form, edit its properties with the property editor, double click on a widget, and be taken to a slot that a widget's signal connects to, all without leaving the IDE.

For Qt 4.0, a Visual Studio .NET integration is available. Work on integration with other IDEs, notably KDevelop and Eclipse, is planned for later Qt 4 releases.

New File Generation Model

Like before, Qt Designer still writes out .ui files that contain the specification of an interface, and uic generates C++ code based on the .ui file. What has changed is that uic now generates a simple struct containing all the widgets and a setupUi() function that creates the widgets and layouts. The struct does not inherit from QObject and is entirely defined in a header file.

There are three approaches to using a form in your application, reflecting the various ways in which standard C++ classes can be combined together.

  • In the direct approach, you simply construct a widget to use as a placeholder for the component, and set up the user interface inside it. For example:

    #include "ui_myform.h" // defines the Ui::MyForm struct
     
    int main(int argc, char *argv[])
    {
        ...
        QDialog dialog;
        Ui::MyForm ui;
        ui.setupUi(&dialog);
        dialog.show();
        ...

  • In the single-inheritance approach, you subclass the form's base class (QWidget or QDialog, for example), and include a private instance of the form's user interface object. For example:

    #ifndef MYFORM_H
    #define MYFORM_H
     
    #include "ui_myform.h"
     
    class MyForm : public QDialog
    {
        Q_OBJECT
     
    public:
        MyForm(QWidget *parent = 0) : QDialog(parent)
        { ui.setupUi(this);
     
    private slots:
        void on_inputSpinBox_valueChanged(int value);
     
    private:
        Ui::MyForm ui;
    };
     
    #endif

  • In the multiple-inheritance approach, you subclass from both the form's base class and the form's user interface object. This allows the widgets defined in the form to be used directly from within the scope of the subclass. For example:

    #ifndef MYFORM_H
    #define MYFORM_H
     
    #include "ui_myform.h"
     
    class MyForm : public QDialog, public Ui::MyForm
    {
        Q_OBJECT
     
    public:
        MyForm(QWidget *parent = 0) : QDialog(parent)
        { setupUi(this);
     
    private slots:
        void on_inputSpinBox_valueChanged(int value);
    };
     
    #endif
The diagram below summarizes how the various files fit together using single or multiple inheritance. This is very similar to subclassing with previous versions of Qt Designer, but this time only one Q_OBJECT class is necessary and uic needs only to generate one file (ui_myform.h).

Designer-Diag3

Another novelty of Qt 4 is that slots that follow a certain naming convention are automatically connected by uic. The naming convention is on_objectName_signalName(), where objectName is the name of the child widget that emits the signal and signalName the name of the signal.

To handle .ui files created with earlier versions of Qt Designer, Qt 4 includes a tool called uic3 that converts old .ui files to the new format (with some help from the Qt3Support library).

Easier Layout Manipulation

Previously, when you wanted to add a widget to an existing layout, you first had to break the old layout, add your widget, and then reapply the layout. With the new Qt Designer, you can simply drag your widget onto the form and if there is a layout, it is automatically inserted into it. Hints help you determine where the widget will end up in the layout.

The grid layout in particular has been improved. Instead of some magic routine that appeared to pick correct positions for widgets, you have the ability to drop the widgets where you please. In addition, you can manipulate the widgets already in the layout so that they have proper stretch factors. It's never been easier to have one widget take the place of two in a layout.

Designer-Grid

The new Qt Designer still lets you add widgets to a form and then group them in a layout. In addition, it is now possible to add the layout first and then add your widgets to the layout.

More Intuitive User Interface

Qt Designer now makes extensive use of drag and drop. This allows us to show a preview of the widget the moment you start the drag instead of just guessing where you want the widget to go. It also allows the user to quickly clone widgets on a form and drag them to other forms.

It is now possible to create custom widgets on the fly that are just a combination of other widgets, simply by dragging them from the form to the tool box. Qt Designer will remember these widgets and make them usable in future forms. The drag and drop interface also makes it possible to drop a widget into an already existing layout and to move widgets around in a grid layout.

Qt Designer now also shows an overview of the connections between widgets. Changing to connection mode will show all the current connections. You can then add new ones by dragging connection lines between them.

We have also made it possible to change the interface of Qt Designer. The trusty old MDI interface is still present, though changed a bit. It is complemented by a new interface that uses top-level windows. If you aren't sure which one you like, you can switch between them on the fly.

Easier Plugins

In addition to being embeddable, Qt Designer is also extensible through plugins. There are interfaces for custom widgets, for special widget editors, for special preferences, and even for your own Qt Designer components. In fact, several of the Qt3Support widgets are provided through plugins. Some examples of how to write your own widget plugins are included in examples/designer.

This is made possible by Qt 4's generic plugin mechanism. In Qt 3, only five types of plugins were supported (image format, SQL driver, style, text codec, and widget plugins). In Qt 4, arbitrary plugins are possible by inheriting from an arbitrary interface and declaring the plugin using the Q_EXPORT_PLUGIN() macro. Qt Designer will then be able to use qobject_cast<>() and load the plugin. See the QPluginLoader class documentation for details.

Conclusion

We have seen the evolution of Qt Designer from some ideas developed by a handful of devoted open source developers to a full-fledged supported application provided by Trolltech which has become an essential tool for creating Qt applications. We encourage you to give it a try in the next version of Qt 4.


Copyright © 2005 Trolltech Trademarks