About widgets

In the Colorpicker program, we only used the widgets QLabel, QSlider, and QSpinBox. However, Qt includes many more of them. As with programming in general, this course material is not attempting to instruct you in using all of them. Instead, we will practice the use of widgets in the following exercises. One of the new widgets you will encounter is QPushButton.

If you are going to continue your studies of software engineering after you have completed this course, it is good for you to familiarize yourself with Qt documentation on widgets, which includes the most recent information about all the widgets in the library.

Parent-child mechanism

First of all, the parent-child mechanism has nothing to do with inheritance but more to do with memory management. The children of a widget are those widgets that lie inside the widget. For example, a dialog may contain buttons and sliders.

The parent-child mechanism is implemented in the class QObject, i.e. it concerns also other objects besides widgets. When we create an object with a parent, the parent adds the object to the list of its children. When the parent is destructed, it goes through this list and destructs each child. This makes the children to destruct their children and so on.

The parent-child mechanism simplifies memory management, since it reduces the risk of memory leaks. The only objects, for which we must call the delete command, are those we created with new and that have no parent. If we destruct a child before its parent, Qt automatically removes that child from the children list of the parent.

Especially for widgets, the parent has an additional meaning: child widgets are shown within the parent’s area. When we delete the parent widget, not only does the child vanish from the memory, it also vanishes from the screen.

Naming objects in Qt

The user interface of the program can be edited during the execution by adding widgets as children of the main window. The widgets that are added like this, i.e. during the execution of the program, do not necessarily have variable names. (Widgets can lack variable names in some other situations as well.)

For these situations, Qt has the option of naming widgets by calling the method setObjectName. After this, it is possible to search for widgets by using the various find methods of the object QObject. On this course we mainly use Qt Designer, and it automatically names objects such as pushButton, pushButton_2, etc. However, it allows you to change object names with the selection changeObjectName in the list of elements on the right.

Widget names are important in the automated tests. They may require that you have used certain names. Because of this, some of the assignments define how you should name the widgets.

User interface with Qt Designer vs. as C++ code

On this course, the widgets were added into the user interface via Qt Designer. This way has some downsides which we will first study with the help of the dice game example. You are familiar with the dice game from the previous programming course. In the game, the user can cast several dice.

../../_images/nopat.png

Since the user interface has the Roll button that handle many QLabel objects in the same way (at the same time), and several Keep buttons working in the same way, nobody wants to edit program code that has stored QLabel objects and QPushButton objects into separate variables (die1, die2, die3, etc.). The best way to implement a set of objects that operate with the same idea is to call the constructor of the widget class in a loop structure, and to store the created objects into a suitable data structure (e.g. vector or map).

While implementing the Tkinter user interfaces, that way of acting was natural because the interface had to be assembled by writing Python program code in any case. After getting to know Qt Designer, you might think it is boring to write the user interface in C++. However, using Qt Designer, we will end up with a set of objects named button1, button2, button3, etc.

When using Qt Designer, it is useful to know that the widgets that are positioned using the layout can be accessed via the method of Qt’s layout objects, itemAt. You can then handle the objects in the loop structure because you know their index in the layout.

Tip

If iterating a certain part of the layout is difficult, you can also use any suitable STL container to store the pointers that point to the widgets you want to handle as a group (i.e. in a similar way).

The other downside is that the user interfaces created with Qt Designer do not scale right when you scale the window larger or smaller. You can see that in the figures below.

../../_images/scaling_bad.png

Scaling Colorpicker implemented with Qt Designer

../../_images/scaling_good.png

Scaling Colorpicker implemented as C++ code

If you implement the user interface in code, you will not need the file with the suffix ui at all. All the widgets are created in program code, just like any other objects. We will practice this way of implementing graphical user interfaces on the next programming course.