In this section, we will sneak peak into one of the key concepts introduced by Qt – Signals and Slots. Qt uses Signals and slots for communicating between objects. Or to be more precise, all objects that derieved from QObjects (or one of its subclasses).
Objects often want to communicate with each other, particularly in GUI programming where different widgets would want to communicate and notify another widget about an event which the recieving widget might be interested in. In Qt, classes (which inherits from QObjects
), emits a signal
when a particular event occurs. Slots
are functions which would be called when a signal is emitted, quite similar to callbacks. Most important fact to note here is that the signal emitting class has no clue on which classes/slots recieve the event, or in other words, they are loosely coupled.Furthermore, they are type-safe.
Let us go ahead and write some sample code. We will first define our Source class, which would emit the signal.
// source.h
#ifndef SOURCE_H
#define SOURCE_H
#include <QObject>
#include <QDebug>
class Source : public QObject
{
Q_OBJECT
QString _message;
public:
explicit Source(QObject *parent = nullptr);
void TriggerEvent();
public slots:
signals:
void messageChanged(QString message);
};
#endif // SOURCE_H
As seen in our header definition, the Source
class has a single signal
, namely messageChanged
, which accepts a QString
parameter. We also have a public method named TriggerEvent()
, which would use to emit the signal. Let us go ahead and define our TriggerEvent()
method.
// source.cpp
#include "source.h"
Source::Source(QObject *parent)
: QObject(parent)
{
}
void Source::TriggerEvent()
{
QString message = "Say Hello !!!";
qInfo() << "Emitting Signal with message "<<message;
emit messageChanged(message);
}
As you can observe, the TriggerEvent
doesn’t do anything fancy. It writes some debug message, before emitting the messageChanged
signal using the emit
call. We are also passing a QString
as required by the method signature.
We will now go ahead define our Destination
class, the one, which is interested in the signal, and contains slots to recieve them.
// Destination.h
#ifndef DESTINATION_H
#define DESTINATION_H
#include <QObject>
#include <QDebug>
class Destination : public QObject
{
Q_OBJECT
public:
explicit Destination(QObject *parent = nullptr);
public slots:
void OnMessageRecieved(QString message);
signals:
};
#endif // DESTINATION_H
The Destination
class has a slot, which has the same signature as the Source
‘s signal messageChanged
. For debugging purpose, let us log some useful information in the slot.
// Destination.cpp
#include "destination.h"
Destination::Destination(QObject *parent)
: QObject{parent}
{
}
void Destination::OnMessageRecieved(QString message)
{
qInfo() << "Recieved Message : " << message;
}
As observed in the above code, the slot merely prints the recieved message using qInfo
.
So far, we have declared the Source
which emits signal and Destination
which declares the slots and recieves the emitted signal. But how does the Qt’s meta-object system know which slots to bind to a signal. This is done using the QObject::connect()
method.
QCoreApplication app(argc, argv);
Source sourceObj(app);
Destination destinationObj(app);
QObject::connect(&sourceObj,&Source::messageChanged,&destinationObj,&Destination::OnMessageRecieved);
sourceObj.TriggerEvent();
The QObject::connect
accepts 4 parameter – reference to the instance of Source class, the signal that is emitted, reference to the instance of Destination class, and the slot in Destination to which the signal needs to be binded.
We then use the Source.TriggerEvent()
method to emit the signal. The Qt’s meta-object system then uses wiring defined by the connect()
method to trigger the slots associated with the signal.
That’s all needed to get started with Signals and Slots. In the next part, we will look into Q_Property
.
One thought on “QT #2 : Signals and Slots”