0

There is a function QObject::sender(), than, when invoked in a slot, provides the QObject* pointer to the sending object.

It's behaviour is far less useful if you have the following structure.

class A : public QObject { Q_OBJECT 
    ...
    signals: 
        void foo(); 
};

class B : public QObject { Q_OBJECT 
    ...
    signals: 
        void foo(); 
};

class C : public QObject { Q_OBJECT
    ... 
    public slots: 
        void bar() { qDebug() << sender(); }  
};

A a; 
B b;
C c;


connect(&A, SIGNAL(foo()), &B, SIGNAL(foo()));
connect(&B, SIGNAL(foo()), &C, SLOT(bar()));

A::whatever() { emit foo(); } 

C::bar() indicates B as the emitter. How can I get the original emitting object, without dealing with all the relays?

Unfortunately QObject::sender() is protected so this naive approach in C::bar() wouldn't compile (not sure if it ever could work, but that's my only idea to traverse the sender() backwards):

QObject *ptr = this;
while ((ptr = ptr->sender()) != NULL)
    qDebug() << ptr->objectName();

To answer some of the questions raised in comments:

  • A - custom widget (lots of dynamically created ones) (holding some data, pointers, whatnot)
  • B - custom top-level UI element (member of the QStackedWidget, handles some UI responsibilities)
  • C - (in practice, C1, C2, C3) - work that needs to be performed (using common state, such as DSP queue) on data stored in As.

Ultimately, A needs to know very little about Cs (or even if anything cares about it's signals). B is where the UI aggregation takes place (also the top-level UI calls Cs to set DSP parameters etc). Cs need to know if sender() is qobject_cast'able to IA interface.

It can be reworked to something along the lines of:

class A : public QObject { Q_OBJECT 
    ...
    signals: 
        void foo(QObject*); 
};

class B : public QObject { Q_OBJECT 
    ...
    signals: 
        void foo(QObject*); 
};

class C : public QObject { Q_OBJECT
    ... 
    public slots: 
        void bar(QObject* mySender) { qDebug() << mySender; }  
};

A a; 
B b;
C c;


connect(&A, SIGNAL(foo(QObject*)), &B, SIGNAL(foo(QObject*)));
connect(&B, SIGNAL(foo(QObject*)), &C, SLOT(bar(QObject*)));

A::whatever() { emit foo(this); } 
qdot
  • 6,195
  • 5
  • 44
  • 95
  • If I understand you correctly, you want to get a sort of "stacktrace" for the emitted signals. I believe signal emitting is a sort of function call. So you want to know which objects' functions were called before it reached your object C? Hm, but why? Anyways, this could be helpful: http://stackoverflow.com/questions/2072013/how-to-intercept-all-signals-emitted-by-a-given-event-in-qt – vahancho Sep 07 '14 at 19:50
  • It's almost a function call. It is however setting the ::sender() pointers at (perhaps) each level of signal indirection - in the simple SIGNAL-SLOT connection, the SLOT can detect which object caused the signal that invoked the SLOT. This can be easily used to do custom multiple callers - slot invocations. I could refactor the SIGNAL() to include QObject* as a parameter, and it will be relayed correctly, but.. it's a cludge. – qdot Sep 07 '14 at 21:04
  • 1
    Well, but why do you need this? Perhaps there is another way to solve your problem? – vahancho Sep 08 '14 at 06:03
  • 1
    The simplest method here is to connect A's signal to C's slot. Why do you need to go via B? It sounds like you should redesign the hierarchy. – TheDarkKnight Sep 08 '14 at 08:26
  • @Merlin069 - answered your concerns in my edit. – qdot Sep 08 '14 at 09:28
  • @vahancho - ditto :) – qdot Sep 08 '14 at 09:28
  • @qdot, You said: "C need to know if sender() is qobject_cast'able to IA interface.". I would say "No" on this. This should be defined in the place where you establish your connections. Function has not to know who calls it. – vahancho Sep 08 '14 at 09:38
  • That's even more confusing. So, you have A (data model) B (UI) C (worker). I would expect B to connect to C and C to connect to A, but not B to A in this instance. So, when a user interacts with the UI, it sets a worker going, which does something, changes the values in the data model and updates the UI. Alternatively, if you're using a Qt data model, the UI gets automatically updated, based upon Qt's Model View Framework: http://qt-project.org/doc/qt-4.8/model-view-programming.html – TheDarkKnight Sep 08 '14 at 09:52
  • @Merlin069 The trick is - not all connections between A and C fire at all times - depending on the UI, we might choose to either disconnect and reconnect all A's to C1, or all A's to C2.. or just reconnect the B-C relay (while using the exact same semantics so it's possible to do A-C connections without UI if the functionality is fixed) – qdot Sep 08 '14 at 10:09
  • @vahancho Perhaps you're right. The Observer-Observable pattern allows the Observer (C) to identify the Observable (A), but, in my explicit passing of `this` as `QObject* mySender` we can make it explicit that the `bar()` works on the parameter instead of implicit data passing. – qdot Sep 08 '14 at 10:12
  • @qdot hello from the past. :) sorry, but how did you solve it at the end? i have the same problem now. my A should know, is he a root reason of changes in C, because C informing A about changes in it. and i have happy loop. :) – Michail Sep 06 '16 at 07:48

0 Answers0