Signals and slots¶
On this round we will use Colorpicker program both as an example
and as a template for an exercise.
Here will study its user interface components and functionalities.
Copy the project from template/12/colorpicker_designer
to student/12/colorpicker_designer
,
and execute the program within it.
Below you can see the user interface of the colorpicker template
and that of the completed version after doing the exercise given in the next Plussa section.
The final user interface of the Colorpicker program has three sliders and three spin boxes that you can use to choose the color components of a color’s RGB value, meaning the amount of red, green, and blue colors. On the screen, there is also a label showing the chosen color, which is formed from the values selected in the user interface components at a certain time. To study the functionality of the program, change the values of the color components and see how it changes the color presented on the screen.
You can conclude that the color label is connected to the values of all sliders, because it changes color when the value of any of the components mentioned above changes.
Signal & slot mechanism¶
In Qt, all the components are implemented by inheriting them
from the class QWidget
, just like QMainWindow
,
mentioned in the previous material section.
Joining user interface components to each other like
described above is done with the so-called signal-slot mechanism.
The simple way to convey this idea is that all the classes inherited from
the class QObject
can send signals and receive them using slots.
Sending a signal is done with the keyword emit
. For example,
a slider could have
emit valueChanged(value_);
or
emit valueChanged(42);
Looking at program code level, the signal looks like a function. If you wish, you can think of sending a signal as a function call. The difference between it and an ordinary function call is that the component sending the signal does not know who/what receives the signal. Also, there can be several receivers.
If you change the values of the sliders in the Colorpicker
program, it causes emitting the signal valueChanged
.
The way Qt works is that sending a signal activates the slots
connected to it.
In the final Colorpicker version, the slider emits the signal
valueChanged
, and that activates the setValue
slot of the
”corresponding” spin box, which in turn changes the value of the spin box.
Similarly, editing the value of a spin box changes both the value of the
”corresponding” slider and the color of the color label.
These relationships can be represented as:
This material is a very simplified presentation of how Qt signals work. In case you wish to get deeper into the matter, we recommend you read the Qt documentation on signals and slots. The Qt documentation explains everything on a general level, whereas this course material uses a single program as the example.
Program code of Colorpicker¶
Let us examine the program code of Colorpicker.
The file main.cpp
is not different to the empty window we examined
on the previous material section.
Therefore, we will start with the file MainWindow.hh
.
As with the previous section, the class MainWindow
is inherited from
QMainWindow
, and the first thing written in its interface is Q_OBJECT
.
Also, the definitions of the constructor and destructor are in
the public interface of the class.
In the section private slots
, you can find those slots that are
implemented in the main window just for the use of the class.
This means that only the class itself can connect signals to them.
If the class additionally had the section public slots
,
it would include signals that you can use from outside the class as well.
The visibility of slot sections is similar to the class interfaces
we learned earlier.
The class MainWindow
has the implementation of the slot onColorChanged
that defines how a window is supposed to work when the user edits
the value of the color.
The private
part of a class contains definitions of the member variables,
just like with other classes.
As we learned on the previous programming course, a user interface
class can have user interface components as its member variables.
You should have as member variables only those user interface components
that you must be able to handle in the program code.
This is why we here have no widgets.
In this case, all widgets have been defined in Qt Designer that
you will learn to use in the next exercise section.
In program code, we can refer to them via the user interface (ui
).
The class interface also includes the constant definition for the maximum value of RGB values.
Next, open the file MainWindow.cpp
.
The initializing list of the constructor initializes all the user interface
components that are member variables, just as we are used to do with
member variables.
We will complete some settings (setMinimum
and setMaximum
) for
the user interface components in the body of the constructor, because
we cannot do that directly in their constructor.
The most important thing to do at the end of the constructor’s body is
connecting each changing signal of a horizontal slider to the
slot onColorChanged
of the MainWindow
object.
We already mentioned the purpose of onColorChanged
.
Your task is to connect the changing signals of the sliders and the spin
boxes in pairs.
The final situation of signals and slots is shown in the previous figure. By comparing the code and the figure, try to find out which connections are already implemented and which connections are left for you to be completed.
At the end of the constructor, we call the slot onColorChanged()
like
we call any function, so that the color of the color label is
changed to the initial value of the color selectors.
The implementation of the slot onColorChanged
is short.
It creates an object of the type QColor
that can be shown in
the object QLabel
.
The RGB value, obtained from the horizontal slider objects,
is passed to the constructor of the object to be created.
At the end, it is good to stop and think about why the slot onColorChanged
was implemented in the class MainWindow
.
However, it is a colorLabel
object that changes color.
The slot must be able to handle horizontal slider objects, which means
it is easiest to implement it in the main window.
The slider objects are children of the main window,
which is why they can be handled in the main window.
(Of course, it would be possible to pass slider objects or references to
them as parameters outside of the class as well, but we will not consider that
solution here.)
Final notes¶
In order to use Qt, the programmer must understand many of the characteristics of the C++ programming language, because all the user interface components are implemented as inherited classes, and the objects created from them are stored using pointers. Now we understand why graphical user interfaces were not the starting topic of this course, even if it would have potentially been nice to study them right after the introduction to graphical user interfaces, studied at the end of the previous programming course.