Unsolved How to identify which signal called the slot?
-
Consider,
connect(this, SIGNAL(signal1(int)), this, SLOT(slot(int))); connect(this, SIGNAL(signal2(int)), this, SLOT(slot(int))); connect(this, SIGNAL(signal3(int)), this, SLOT(slot(int))); connect(this, SIGNAL(signal4(int)), this, SLOT(slot(int))); connect(this, SIGNAL(signal5(int)), this, SLOT(slot(int)));
slot(int) is connected to signals 1,2,3,4,5 .
How to get the signal which called the slot? (identify inside the slot)?
Here the sender is same for all the signals.
How to identify the same(prev question) for signals from multiple sender objects?
-
The only way is to pass that info as a signal/slot parameter. It goes against the design of signals/slots to do so though. Receiver should not have to know anything about the sender, and, in particular, there might not be a sender at all if the slot was called directly.
What are you trying to do exactly? -
QSignalMapper provides a way to solve this: http://doc.qt.io/qt-5/qsignalmapper.html
There is also an example how this class works.
-
@aha_1980 QSignalMapper can't help you if the signal has parameters like in OP's example.
-
@Chris-Kawa: ah, right.
in this case, using a lambda like suggested in https://stackoverflow.com/questions/13989297/how-to-keep-the-source-signals-parameters-while-using-qsignalmapper might be the solution.
-
@aha_1980 If you're gonna use a lambda you might as well just change the signature of the signal/slot, like I mentioned in my first response. In any case my point still stands - this is a bad design as it forces sender and receiver to know about each other and thus creates tight coupling.
-
@Chris-Kawa said in How to identify which signal called the slot?:
If you're gonna use a lambda you might as well just change the signature of the signal/slot
That is only possible if you can change the sender object. There might be cases where you can't (at least not with lots of effort).
In any case my point still stands - this is a bad design as it forces sender and receiver to know about each other
The sender does not need to (and should not, I fully agree to you) know anything about the receiver. But the receiver needs to do something when the signal is emitted, so for a program (I'm not talking about libraries here) the slot will contain logic to process data when the signal happens. There are real world cases where one slot handles the signals of multiple objects, so I don't see why this should be forbidden.
and thus creates tight coupling.
As said, I'm talking about a program. For libraries, your point is valid.
-
@aha_1980 said in How to identify which signal called the slot?:
There are real world cases where one slot handles the signals of multiple objects, so I don't see why this should be forbidden
Nothing is forbidden. But I agree with @Chris-Kawa that the receiver should not have to know who emit the signal to do its work. Why should the receiver need this information to do its work? The behaviour and needed data are usually specified using signal/slot parameters not through knowing who emit the signal. Forcing receiver to know who emit the signal introduces tight coupling which is bad design.
-
Even so I agree with the previous posters. QObject actually has an inbuild function to handle this situation:
Make sure to pay attention to the warnings!
-
@J-Hilk OP already mentioned he can't use
sender()
because it's the same in all cases.Ok, so to give a concrete example instead of "do this, don't do that" here's the usual response people asking this question fish for. It's the pattern @aha_1980 suggested:
enum WhoSentIt { Signal1, Signal2 }; connect(this, &SomeClass:signal1, this, [=](int param){ slot(param, WhoSentIt::Signal1); }); connect(this, &SomeClass:signal2, this, [=](int param){ slot(param, WhoSentIt::Signal2); }); void SomeClass::slot(int param, WhoSentIt source) { if (source == WhoSentIt::Signal1) doSomething(param); else if (source == WhoSentIt::Signal2) doSomethingElse(param); }
This is in my view the wrong approach. It adds unnecessary complexity, introduces branching, hinders readability, testability and mixes concerns.
What I'm saying is it's better to do this:connect(this, &SomeClass:signal1, this, &SomeClass:doSomething); connect(this, &SomeClass:signal2, this, &SomeClass:doSomethingElse);
Shorter, simpler, easier to test and doesn't introduce artificial coupling.