Jump to content


Check out our Community Blogs

Register and join over 40,000 other developers!


Recent Status Updates

View All Updates

Photo
- - - - -

Qt: Part2 -- Signal & Slot

java

  • Please log in to reply
2 replies to this topic

#1 kernelcoder

kernelcoder

    CC Devotee

  • Expert Member
  • PipPipPipPipPipPip
  • 990 posts
  • Location:Dhaka
  • Programming Language:C, Java, C++, C#, Visual Basic .NET
  • Learning:Objective-C, PHP, Python, Delphi/Object Pascal

Posted 08 July 2012 - 10:11 AM

Abstract
This is part 2 of a series of tutorials about Qt. In 'Part1' we just talked about what Qt is and installing it. In this part we'll know about Signal & Slot in Qt. I'll try my best to arrange & prepare he tutorials for absolutely beginners to Qt.

We know that 'Object' is the core of OOP programming paradigm and so as in Qt. One of the core features of Qt is 'Signal & Slot'. 'Signal & Slot' is the mechanism for communicating between objects. In most older libraries, this communication is performed with 'callback' and 'callback handler'. Signal and Slot is smarter/shorter ways of communication than callback/callback-handler. Actually under the hood, all things are just callback and callback handler but Signal and Slot is a intelligent wrapper to it. If we want to find similarity of signal & slot in Qt with .NET & Java, it is similar to .NET's event delegation and Java's action/action-listener.



The Signal
We know that in a communication there are two parties -- Sender and Receiver. Signal is the 'thing' that sender emits to let other receiver(s) know there there is something happened or some state changed in sender and knowing that the receivers can 'execute' something base on that signaling from sender. As example, and a window is closing, it may signal that 'it is going to close itself' so that based on the that signaling other objects in the system can do something which is related/dependent to that 'window's existence.
From the view of code, the 'signal' is just a declaration of a method under the 'signals' access-specifier. I repeat just a declaration; no definition. And when it is time to raise/fire the signal from a line of code, just call that method from that particular point of code . The signal firing/raising differs from normal method calling in the sense that we need to put a special keyword before that method calling -- that keyword is 'emit'. As example, here is a signal declaration and raising/firing that signal.
class Sender : public QObject 
{
    Q_OBJECT
public:
    Sender(QObject* parent = 0 ) : QObject(parent)
    {
    }


signals: /* signals to be declared under 'signals' access specifier */
   void foo();  /* This is a signal declaration -- a pure declaration as a method.*/


public:
   void method1()
   {
        /* some lines of code executed before this line*/

         emit foo(); /* This is the firing/raising of the signal 'foo'. */

        /* some lines of code executed after this line*/
   }
};




The Slot
Slot is the piece of code (actually a method) that will be called when the particular signal(s) are emitted. This is the method in the receives end (in receiver class). So a slot gets called when the signals connected to the slot are emitted. A slot is a normal C++ method and even can be called as a normal method. The only special feature is that this special methods can be connected to signals. Slots can be under any access specifier but that specifier should be marked with special keyword -- 'slots'. Slots under any access specifier can be connected to any signal. The access specifier affects when you try to call it as a normal method. As examples, slots are defined in code as:

class Receiver: public QObject 
{
    Q_OBJECT
public:
    Sender(QObject* parent = 0 ) : QObject(parent)
    {
    }


public slots:
   void bar1() { }  /* This is a public slot*/


protected slots:
   void bar2() { }  /* This is a protected slot*/


private slots:
   void bar3() { }  /* This is private slot */
};




Conditions to Write Signals & Slots in Your Own Class
If you want to write signals & slots in your own class, you need to meet two conditions...
  • Your class must inherit from QObject class or any class derived from QObject.
  • The Q_OBJECT macro must appear in a private section in your class.
Note that we met those two conditions in the above Sender and Receiver class.




Connecting/Binding the Signal to Slot
Well, after declaring/defining signals and slots in sender/receiver class, we need to connect/bind the signals and slots to each so other so that when signal emits, slots gets called. We use connect method of the QObject class to do that. We usually need for major arguments to provide to that method to connect/bind a signal to a slot ---
  • sender: the sender of the signal
  • signal: the signal from the sender object that we want to connect to
  • receiver: the receiver object on which the slot will be executed when the signal emits
  • method: the slot in the receiver object that will get called with the signal emits int the sender object.
So he following code connects the foo signal of Sender class to bar slot of Receiver class.
Sender sender;
Receiver receiver;
QObject::connect(&sender, SIGNAL(foo()), &receiver, SLOT(bar()));
The SIGNAL and SLOT macro prepare a string of method that we need to pass to QObject::connect method.





Signals & Slots in Effect
Let us now create a simple program that will use the signal and slot. Follow the steps to create a console application in Qt-Creator. Note that I'm using QtCreator 2.2.1 with Qt Framework 4.7.4.
  • Lunch QtCreator and go to 'File --> New File or Project' menu. 'New' window will appear on you.
  • In the window, select 'Other Project' from the left-top section and 'Qt Console Application' from the right section and click on 'Choose' button. qt_create_project.PNG
  • 'Qt Console Application' window will appear on you. Select a path and give a name to our project. As example, I named it SignalSlotTesting. Then click on 'Next' button. qt_create_project2.PNG
  • In the next page, you need to select the 'Target' devices your project will run/deploy on. You can select multiple if you want. For this example select only 'Desktop' as target. And click on 'Next' button. In the next page, click on 'Finish' button.qt_create_project3.PNG
  • This is our project at this stage in QtCreator -- qt_create_project_final.PNG
Now let us add a class -- Sender -- in the project. Follow the steps below.
  • Right click on project node 'SignalSlotTesting' in the project explorer -- > Add New.... qt_add_class_1.PNG
  • In the 'New File' window, select 'C++' from the 'Choose a template' section and 'C++ Class' from the right section and click on 'Choose' button.qt_add_class_2.PNG
  • 'C++ Class Wizard' will be on you: In this wizard, give our class name to 'Sender', write QObject as base class and inherit type information from QObject class. And click on 'Next' button. In the next page, click on 'Finish' button.
Let us also add another class -- Receiver -- following all the steps we did for Sender class. qt_add_class_4.PNG


Code in Sender.h/.cpp file
/* Sender.h */

#ifndef SENDER_H
#define SENDER_H

#include <QObject>

class Sender : public QObject
{
    Q_OBJECT
public:
    explicit Sender(QObject *parent = 0);    
    void fireSignal();

signals:
    void foo(const QString& arg);
};

#endif // SENDER_H


/* Sender.cpp*/


#include "Sender.h"

Sender::Sender(QObject *parent) :
    QObject(parent)
{
}


void Sender::fireSignal()
{
    emit foo("This a message sender is sending to receiver.");
}



Code in Receiver .h/.cpp file
/* Receiver.h */

#ifndef RECEIVER_H
#define RECEIVER_H

#include <QObject>

class Receiver : public QObject
{
    Q_OBJECT
public:
    explicit Receiver(QObject *parent = 0);

public slots:
    void bar(const QString& arg);

};

#endif // RECEIVER_H

/* Receiver.cpp */

#include "Receiver.h"
#include <iostream>

Receiver::Receiver(QObject *parent) :
    QObject(parent)
{
}


void Receiver::bar(const QString &arg)
{
    std::cout << arg.toStdString();
}


Code in main.cpp file
#include <QtCore/QCoreApplication>
#include "Sender.h"
#include "Receiver.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    Sender sender;
    Receiver receiver;

    QObject::connect(&sender, SIGNAL(foo(QString)), &receiver, SLOT(bar(QString)));

    sender.fireSignal();

    return a.exec();
}

So what we did in main is: We created instance of Sender and Receiver. Then connected the foo signal from Sender object to bar slot of Receiver object. And then we call the normal method fireSignal to sender. Now, sender object emits the foo signal in that method and the bar slot is called in receiver method. And this is the purpose of signal and slot.

Note that I have not yet said about the fifth argument to QObject::connect method -- the Qt::ConnectionType. I'll discuss that in a later part of this tutorial series. I think this is enough about signal & slot for a beginner in a single tutorial.

Back soon with next part :)
  • 1

#2 mdminhazulhaque

mdminhazulhaque

    CC Lurker

  • New Member
  • Pip
  • 6 posts
  • Location:Rajshahi
  • Programming Language:C, C++, PHP, PL/SQL, Bash
  • Learning:JavaScript, Ruby, Assembly

Posted 23 November 2012 - 03:42 AM

It took more than one month to understand what is signal and slot in Qt. Later I learned that this is one of the coolest features of Qt. Simply, signal-and-slot is the process or connecting several objects. If I could find this post, I would do better then.

Thank you for this awesome intro. :thumbup1:
  • 1

#3 pinkerton

pinkerton

    CC Lurker

  • Just Joined
  • Pip
  • 1 posts

Posted 09 July 2014 - 01:15 PM

Thanks for that great writeup. I spent most of the day trying to get my connect( ) to work. I read and read and looked at code examples, but none of them did it. You happened to mention that the slot function method needed to be listed under the keyword slot. Bingo. Ended my day with a smile. Thanks for taking the time to write up this article and do all of the work formatting etc.

 

Kevin


  • 0





Also tagged with one or more of these keywords: java