Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Qt signals and slots in different classes

I have a class X with a slot, and a class Y with a signal. I'm setting up the connection from class X, and created a public method in class Y to emit the signal from class X (I'm not sure this step was necessary).

Then, if I call that method from class X, signal is emitted, and slot is executed. But if I emit signal from class Y, slot is never executed and I don't understand why.

May I stablish connection also at class Y?

This pseudo-code tries to explain what I want:

class X  : public QWidget {
    Q_OBJECT

X(){
    connect(Y::getInstance(), SIGNAL(updateSignal(int)), this, SLOT(updateStatus(int)));
    Y::getInstance().emitSignal(someValue); // Works
}

public slots:
    void updateStatus(int value);

}

class Y : public QObject {

Q_OBJECT

Y(){

}

public:
    Y getInstance();
    void emitSignal(int value) { 
        emit updateSignal(value);
    }


signal:
    void updateSignal(int value);
}

class Z : public Y {
Z(){

}

init(){
 emitSignal(someValue); // Doesn't work
}
}
like image 448
Roman Rdgz Avatar asked Jun 05 '12 10:06

Roman Rdgz


2 Answers

Remember that connections are not between classes, but between instances. If you emit a signal and expect connected slots to be called, it must be emitted on an instance on which the connection was made. That's your problem.

Assuming Y is a Singleton:

If you do connect( Y::getInstance(), ... )

and Y::getInstance() does new Y() at some point, then the constructor of Y is called before the connection is set up. Like that, the signal will be emitted but the slot will not listen to it yet.

Apart from that, it would be best to do one of the following things, though you could not emit the signal in the constructor of Y with these approaches:

  • Use a third class Z that knows both X and Y, and do the connection there
  • Dependency Injection. That means X gets an instance of Y in its constructor:

Example for a Dependency Injection Constructor:

X::X( Y* const otherClass )
{
    connect( otherClass, SIGNAL( ... ), this, SLOT( ... )
}
like image 126
Tim Meyer Avatar answered Nov 04 '22 08:11

Tim Meyer


Its simple. Please see below example.

If you want to write signals & slots in your own class, you need to meet two conditions...

1. Your class must inherit from QObject class or any class derived from QObject.

2. The Q_OBJECT macro must appear in a private section in your class.

/* 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.");
}

Now receiver's code below

/* 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();
}

Now main.cpp code

#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();
}

That's it.

Finally if you want to use another syntax for connect method. Please use the below lines

QObject::connect(&sender,&Sender::foo,&receiver,&Receiver::bar);

Hope this helped you. Thanks

like image 31
loyola Avatar answered Nov 04 '22 08:11

loyola