5

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
}
}
Roman Rdgz
  • 11,378
  • 36
  • 110
  • 192
  • 1
    can you provide some code? i can`t understand exactly what you are trying to say –  Jun 05 '12 at 11:02
  • No, you need to establish a connection only once. Please post some of your code. – Ammar Jun 05 '12 at 11:06
  • It's very complex code, so I'll post some pseudo to explain the question better – Roman Rdgz Jun 05 '12 at 11:14
  • 1
    Well from your simplified code it looks like you're trying to emit the signal in the constructor, where the connection isn't done yet. May be just a simplification artefact though. – Torp Jun 05 '12 at 11:20
  • Does an instance of object X exist at the time when init() is called? (I don't see X instantiated anywhere in your pseudo/simplified code.) – roop Jun 05 '12 at 12:16
  • The function `getInstance()` should return a pointer, or prepend the `&` operator in the `connect()` call – felixgaal Jun 05 '12 at 18:26

3 Answers3

7

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( ... )
}
Community
  • 1
  • 1
Tim Meyer
  • 10,998
  • 7
  • 48
  • 84
4

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

loyola
  • 3,315
  • 2
  • 20
  • 18
0

You are emitting signal from the constructor. At that time Y::getInstance() has no meaning ACCORDING TO THIS code fragment.

shan
  • 1,084
  • 3
  • 13
  • 27
  • It's just a simplification. I do get the Y instance right. If not, I wouldn't say emitSignal works from X – Roman Rdgz Jun 05 '12 at 11:25
  • Yes. you are calling `Y::getInstance().emitSignal(someValue);` from X. It works because at that time you have a object of Y. But you can't do that from the Y's constructor. – shan Jun 05 '12 at 11:29
  • Ok, it is not happening at the constructor, it's happening at other part of Y's code. Anyway I can't see why I can't call a Y's method from Y's constructor – Roman Rdgz Jun 05 '12 at 11:31
  • Its not about calling a method from the constructor. Its about Qt's connecting mechanism... :) – shan Jun 05 '12 at 11:33
  • Signals/slots don't work until after a connect() is executed. The constructor of Y is called at the moment of the first getInstance(), does emit() but the signal is not connected to anything, and only THEN the connect call executes and links the signal to the slot. – Torp Jun 05 '12 at 11:38
  • Ok, that's a good reason why it shouldn't work at the ctor, but it does not explain why it is not working at any other point which get executted after the connect, since the code shown is just a simplification. Y is already created when X is created and connection is made. Then, some methods from Y are executed and trying to emit the signal, but the slot is not executed. – Roman Rdgz Jun 05 '12 at 11:41
  • That's why i have pressed "Caps Lock" while typing the answer. Post some code that we can analyze further... – shan Jun 05 '12 at 11:46
  • 1
    Ah I see you're inheriting from Y etc... connect() works on instances not on classes... maybe the instance gets messed up somewhere in the inheritance chain. You can even follow the emit() in a debugger to see what happens with a debug Qt. – Torp Jun 05 '12 at 11:50
  • Ok @Torp that is the kind of clue I was looking for, since it's nearly impossible to show a short example of how my code looks now. – Roman Rdgz Jun 05 '12 at 12:43
  • 1
    Also, connect() returns true or false. If you log those you may find out fast enough where it fails :) emit() on the other hand does not error out if there is no slot connected to its signal. – Torp Jun 05 '12 at 12:47