Using a Designer UI File in Your Application

<Unknown command>contentspage{Qt Designer Manual}{Contents}

Qt Designer UI files represent the widget tree of the form in XML format. The forms can be processed:

  • At compile time, which means that forms are converted to C++ code that can be compiled.

  • At runtime, which means that forms are processed by the QUiLoader class that dynamically constructs the widget tree while parsing the XML file.

Compile Time Form Processing

You create user interface components with Qt Designer and use Qt's integrated build tools, qmake and uic, to generate code for them when the application is built. The generated code contains the form's user interface object. It is a C++ struct that contains:

  • Pointers to the form's widgets, layouts, layout items, button groups, and actions.

  • A member function called setupUi() to build the widget tree on the parent widget.

  • A member function called retranslateUi() that handles the translation of the string properties of the form. For more information, see Reacting to Language Changes.

The generated code can be included in your application and used directly from it. Alternatively, you can use it to extend subclasses of standard widgets.

A compile time processed form can be used in your application with one of the following approaches:

  • The Direct Approach: you construct a widget to use as a placeholder for the component, and set up the user interface inside it.

  • 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.

  • The Multiple Inheritance Approach: you subclass 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.

To demonstrate, we create a simple Calculator Form application. It is based on the original Calculator Form example.

The application consists of one source file, main.cpp and a UI file.

The calculatorform.ui file designed with Qt Designer is shown below:

Image non disponible

We will use qmake to build the executable, so we need to write a .pro file:

 
Sélectionnez
HEADERS     = calculatorform.h

The special feature of this file is the FORMS declaration that tells qmake which files to process with uic. In this case, the calculatorform.ui file is used to create a ui_calculatorform.h file that can be used by any file listed in the SOURCES declaration.

You can use Qt Creator to create the Calculator Form project. It automatically generates the main.cpp, UI, and .pro files, which you can then modify.

The Direct Approach

To use the direct approach, we include the ui_calculatorform.h file directly in main.cpp:

 
Sélectionnez
#include "ui_calculatorform.h"

The main function creates the calculator widget by constructing a standard QWidget that we use to host the user interface described by the calculatorform.ui file.

 
Sélectionnez
int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    QWidget widget;
    Ui::CalculatorForm ui;
    ui.setupUi(&amp;widget);

    widget.show();
    return app.exec();
}

In this case, the Ui::CalculatorForm is an interface description object from the ui_calculatorform.h file that sets up all the dialog's widgets and the connections between its signals and slots.

The direct approach provides a quick and easy way to use simple, self-contained components in your applications. However, componens created with Qt Designer often require close integration with the rest of the application code. For instance, the CalculatorForm code provided above will compile and run, but the QSpinBox objects will not interact with the QLabel as we need a custom slot to carry out the add operation and display the result in the QLabel. To achieve this, we need to use the single inheritance approach.

The Single Inheritance Approach

To use the single inheritance approach, we subclass a standard Qt widget and include a private instance of the form's user interface object. This can take the form of:

  • A member variable

  • A pointer member variable

Using a Member Variable

In this approach, we subclass a Qt widget and set up the user interface from within the constructor. Components used in this way expose the widgets and layouts used in the form to the Qt widget subclass, and provide a standard system for making signal and slot connections between the user interface and other objects in your application. The generated Ui::CalculatorForm structure is a member of the class.

This approach is used in the Calculator Form example.

To ensure that we can use the user interface, we need to include the header file that uic generates before referring to Ui::CalculatorForm:

 
Sélectionnez
#include "ui_calculatorform.h"

This means that the .pro file must be updated to include calculatorform.h:

 
Sélectionnez
HEADERS     = calculatorform.h

The subclass is defined in the following way:

 
Sélectionnez
class CalculatorForm : public QWidget
{
    Q_OBJECT

public:
    explicit CalculatorForm(QWidget *parent = nullptr);

private slots:
    void on_inputSpinBox1_valueChanged(int value);
    void on_inputSpinBox2_valueChanged(int value);

private:
    Ui::CalculatorForm ui;
};

The important feature of the class is the private ui object which provides the code for setting up and managing the user interface.

The constructor for the subclass constructs and configures all the widgets and layouts for the dialog just by calling the ui object's setupUi() function. Once this has been done, it is possible to modify the user interface as needed.

 
Sélectionnez
CalculatorForm::CalculatorForm(QWidget *parent)
    : QWidget(parent)
{
    ui.setupUi(this);
}

We can connect signals and slots in user interface widgets in the usual way by adding the on_<object name> - prefix. For more information, see widgets-and-dialogs-with-auto-connect.

The advantages of this approach are its simple use of inheritance to provide a QWidget-based interface, and its encapsulation of the user interface widget variables within the ui data member. We can use this method to define a number of user interfaces within the same widget, each of which is contained within its own namespace, and overlay (or compose) them. This approach can be used to create individual tabs from existing forms, for example.

Using a Pointer Member Variable

Alternatively, the Ui::CalculatorForm structure can be made a pointer member of the class. The header then looks as follows:

 
Sélectionnez
namespace Ui {
    class CalculatorForm;
}

class CalculatorForm : public QWidget
...
virtual ~CalculatorForm();
...
private:
    Ui::CalculatorForm *ui;
...

The corresponding source file looks as follows: