Qt for beginners Signals and slots: Difference between revisions

From Qt Wiki
Jump to navigation Jump to search
(Add "cleanup" tag)
(Redirect to Qt for Beginners (Merged))
 
(3 intermediate revisions by 2 users not shown)
Line 1: Line 1:
{{Cleanup | reason=Auto-imported from ExpressionEngine.}}
#REDIRECT [[Qt for Beginners]]
 
[toc align_right="yes" depth="3"]
[[Category:Qt_for_beginners]]
[[Category:Tutorial]]
[[Category:HowTo]]
 
= Qt for beginners — Signals and slots =
 
[[Qt_for_beginners_pretty_button|<<< A pretty button]] | [[Qt_for_beginners|Summary]] | [[Qt_for_beginners_Signals_and_slots_2|Signals and slots 2 >>>]]
 
'''''Note:''' Unfortunately, the images are no longer available. See the official "Getting Started with Qt Widgets":http://doc.qt.io/qt-5/gettingstartedqt.html page for an alternative tutorial.''
 
This chapter covers a very useful and important feature of QT called signals and slots.
 
== Introduction ==
 
=== The observer pattern ===
 
Nearly all UI toolkits have a mechanism to detect a user action, and respond to this action. Some of them use ''callbacks'', others use ''listeners'', but basically, all of them are inspired by the "observer pattern":http://en.wikipedia.org/wiki/Observer_pattern.
 
Observer pattern is used when an ''observable'' object wants to notify other ''observers'' objects about a state change. Here are some concrete examples :
* A user has clicked on a button, and a menu should be displayed.
* A web page just finished loading, and a process should extract some information from this loaded page.
* An user is scrolling through a list of items (in an app store for example), and reached the end, so other items should be loaded.
 
Observer pattern is used everywhere in GUI application, and often lead to some "boilerplate code":http://en.wikipedia.org/wiki/Boilerplate_code. Qt was created with the idea of removing these boilerplate code and providing a nice and clean syntax, and the signal and slots mechanism is the answer.
 
=== Signals and slots ===
 
Instead of having observable and observers, and registering them, Qt provides two high level tools : '''signals''' and '''slots'''.
 
* A '''signal''' is a message that an object can send, most of the time to inform of a status change.
* A '''slot''' is a function that is used to respond to a signal.
 
Here are some example of signals and slots from our well known [[Doc:QPushButton]] class.
 
* ''clicked''
* ''pressed''
* ''released''
 
As you can see, their names are quite explicit. These signals are sent when the user clicked (pressed then released) , pressed or released the button.
 
Here are some slots, from different classes
 
* QApplication::''quit''
* QWidget::''setEnabled''
* QPushButton::''setText''
 
In order to respond to a signal, a slot must be ''connected'' to a signal. Qt provides the method QObject::'''connect'''. It is used this way, with the two macros '''<code>SIGNAL</code>''' and '''<code>SLOT</code>'''
<code>
FooObjectA *fooA = new FooObjectA();
FooObjectB *fooB = new FooObjectB();
 
QObject::connect(fooA, SIGNAL (bared()), fooB, SLOT (baz()));
</code>
 
assuming that <code>FooObjectA</code> have a <code>bared</code> signal, and <code>FooObjectB</code> have a <code>baz</code> slot.
 
You have to write the signature of the signal and the slot inside the two macros ''SIGNAL'' and ''SLOT''. If you want to get some information about what these macros do, please read the last section of this chapter.
 
'''Remark''' : Basically, signals and slots are methods, that might or might not have arguments, but that never return anything. While the notion of a signal as a method is generally quite blur, a slot is actually a real method, and can be called as usual in other methods, or while respoing to a signal.
 
=== Transmitting information ===
 
The signals and slots mechanism is useful to respond to buttons clicks, but it can do much more than that. For example, It can also be used communicate information. Lets say while playing a song, a progress bar is needed to show how much time remains before the song is over. A media player might have a class that is used to check the progress of the media. An instance of this class might periodically send a ''tick'' signal, with the progress. This signal can be connected to a [[Doc:QProgressBar]], that can be used to display the progress.
 
The hypothetical class used to check the progress might have a signal that have this signature :
 
<code>
void MediaProgressManager::tick(int miliseconds);
</code>
 
and we know from the documentation, that the QProgressBar have this slot
 
<code>
void QProgressBar::setValue(int value);
</code>
 
You can see that the signal and the slot have the same kind of parameters, especially the type. If you connect a signal to a slot that do not share the same kind of parameters, while the connection is done (at run-time) you will get a warning like
 
<code>
QObject::connect: Incompatible sender/receiver arguments
</code>
 
It is because the signal transmits the information to the slot using the parameters. The first parameter of the signal is passed to the first one of the slot, and the same for second, third, and so forth.
 
[[Image:http://farm8.staticflickr.com/7253/7514122680_7be76c3027_z.jpg|signal-slot connection]]
 
The code for the connection will look like this:
 
<code>
MediaProgressManager *manager = new MediaProgressManager();
QProgressBar '''progress = new QProgressBar(window);
 
QObject::connect(manager, SIGNAL (tick(int)), fooB, SLOT (setValue(int)));
</code>
 
You can see that you have to provide a signature inside the ''SIGNAL'' and ''SLOT'' macro, providing the type of the value that are passed through the signals. You may not provide the name of the variable if you want. (It is actually even better).
 
h3. Features of signals and slots
 
''' A signal can be connected to several slots
* Many signals can be connected to a slot
* A signal can be connected to a signal : it is signal relaying. The second signal is send if the first signal is sent.
 
== Examples ==
 
=== Responding to an event ===
 
Remember our button app ? Let's try to actually make something with this app, like be able to close it while clicking on the button. We already know that [[Doc:QPushButton]] provides the ''clicked'' signal. We also have to know that [[Doc:QApplication]] provides the ''quit'' slot, that closes the application.
 
In order to make a click on a button to close the app, we have to connect the signal ''clicked'' of the button to the ''quit'' slot of QApplication instance. We can modify the code from previous chapter to do this, but before, you might wonder how to access to the QApplication instance while you are in another class. Actually, it is pretty simple, since there exists a static function in [[Doc:QApplication]], with the following signature, that is used to get it
 
<code>
QApplication * QApplication::instance()
</code>
 
This leads to the following modification of our previous code
 
''window.cpp''
<code>
#include "window.h"
 
#include <QPushButton>
#include <QApplication>
 
Window::Window(QWidget '''parent) :
QWidget(parent)
{
// Set size of the window
setFixedSize(100, 50);
 
// Create and position the button
m_button = new QPushButton("Hello World", this);
m_button->setGeometry(10, 10, 80, 30);
 
// NEW : Do the connection
connect(m_button, SIGNAL (clicked()), QApplication::instance(), SLOT (quit()));
}
 
</code>
 
While clicking on the button inside of the window, the application should quit.
 
h3. Transmitting information with signals and slots
 
Here is a simpler example for information transmission. It only displays a progress bar and a slider (created by [[Doc:QSlider]]) inside a window, and while the slider is moved, the value of the progress bar is synced with a very simple connection.
 
The interesting signals and slots are
 
<code>
void QSlider::valueChanged(int value);
void QProgressBar::setValue(int value);
</code>
 
QSlider automatically emits the signal <code>valueChanged</code> with the new value passed as parameter while the value is changed, and the method <code>setValue</code> of QProgressBar, is used, as we have seen, to set the value of the progress bar.
 
This leads to the following code
 
<code>
#include <QApplication>
#include <QProgressBar>
#include <QSlider>
 
int main(int argc, char'''*argv)
{
QApplication app (argc, argv);
 
// Create a container window
QWidget window;
window.setFixedSize(200, 80);
 
// Create a progress bar
// with the range between 0 and 100, and a starting value of 0
QProgressBar *progressBar = new QProgressBar(&amp;window);
progressBar->setRange(0, 100);
progressBar->setValue(0);
progressBar->setGeometry(10, 10, 180, 30);
 
// Create a horizontal slider
// with the range between 0 and 100, and a starting value of 0
QSlider *slider = new QSlider(&amp;window);
slider->setOrientation(Qt::Horizontal);
slider->setRange(0, 100);
slider->setValue(0);
slider->setGeometry(10, 40, 180, 30);
 
window.show();
 
// Connection
// This connection set the value of the progress bar
// while the slider's value changes
QObject::connect(slider, SIGNAL (valueChanged(int)), progressBar, SLOT (setValue(int)));
 
return app.exec();
}
</code>
 
== Technical aspect ==
 
This section can be skipped for now if you only want to program with Qt. Just know that you need to put '''SIGNAL''' and '''SLOT''' around the signals and slots while calling <code>connect</code>. If you want to know how Qt works, it is better to read this.
 
=== The meta-object ===
 
Qt provides a ''meta-object'' system. Meta-object (literally "over the object") is a way to achieve some programming paradigms that are normally impossible to achieve with pure C++ like
 
* '''Introspection''' : capability of examining a type at run-time
* '''Asynchronous function calls'''
 
To use such meta-object capabilites in an application, one can subclass [[Doc:QObject] and mark it so that the meta-object compiler (moc), can interpret and translate it.
 
Code produced by moc includes signals and slots signatures, methods that are used to retrieve meta-information from those marked classes, properties handling … All these information can be accessed using the following method
 
<code>
const QMetaObject * QObject::metaObject () const
</code>
 
[[Doc:QMetaObject]] class contains all the methods that deals with meta-object.
 
=== Important macros ===
 
The most important macro is '''Q_OBJECT'''. Signal - Slot connections and their syntax cannot be intepreted by regular C++ compiler. The moc is provided to translate the QT syntax like "connect", "signals", "slots", etc into regular C++ syntax.
This is done by specifying the '''Q_OBJECT''' macro in the header containing class definitions that use such syntax.
 
''mywidget.h''
<code>
class MyWidget : public QWidget
{
Q_OBJECT
public:
MyWidget(QWidget '''parent = 0);
}
</code>
 
Others marker macros for moc are
''' '''signals'''
* public / protected / private '''slots'''
 
that mark the different methods that need to be extended.
 
'''SIGNAL''' and '''SLOT''' are also two very important and useful macros. When a signal is emitted, the metao-bject system is used to compare the signature of the signal, to check connection, and to find the slot using it's signature. These macros are actually used to convert the provided method signature into a string that match the one stored in the metaobject.

Latest revision as of 14:35, 5 May 2015

Redirect to: