When to use signals and slots, versus direct function calls, from parent to child?
-
Thanks, all, for your answers so far. I'm looking at a very specific case from Qt's QAbstractButton, and trying to decide how I would implement some of its operations if I were designing it -- i.e., best practices. SetIcon() is a direct function call, whereas the very similar-sounding SetIconSize() is a slot. SetCheckable() is a function call, but SetChecked() is a slot. These use cases all seem very similar conceptually, yet some are function calls and some are slots. It's not obvious what the differences are. Even considering the suggestions given so far, I'm not sure how they would lead an outsider to make the same choices. Maybe it does not really matter much in many situations, and I'm just overthinking it.
-
@JohnB
There is nothing special about a slot, only a signal. A slot is just a function, you can call it directly any time you like, nothing to do with signals. The fact that Qt has chosen to classify some methods as slots essentially only means that it would not be surprising if you used them as the slots for signals. A slot ought not to return a value insofar as that cannot be used if it is called from a signal, though it could do if called directly, but since it is intended to be useful from a signal it really ought bevoid
and not take "out" parameters.Don't worry too much about slots, only about signals.
-
@JoeCFD said in When to use signals and slots, versus direct function calls, from parent to child?:
The recipient knows the sender and can use it to call back or send a signal back.
But that is not at all the same thing as a direct function call, e.g. with a return result and/or "out" parameters. Nor is it the same if
connect()
s are anything other thanDirectConnection
.I don't know what you mean about "The recipient knows the sender". Do you mean via QObject *QObject::sender() const? Which is not a great idea to use, has cases where it is not valid/available as per the docs and, I believe, other cases where it is not valid either. As I'm sure you know :)
-
@JoeCFD
:) Let's put it this way: for the OP trying to get to grips with Qt, signals and slots, I think you would agree we should not be encouraging them to usesender()
or know anything about the sender at this stage.As an aside, using a lambda with a parameter or even a
QSignalMapper
seems a cleaner way of passing information about the sender to the receiver, if it is really needed. But I still think this is "advanced" for the initial level the OP is at. -
@JonB said in When to use signals and slots, versus direct function calls, from parent to child?:
:) Let's put it this way: for the OP trying to get to grips with Qt, signals and slots, I think you would agree we should not be encouraging them to use sender() or know anything about the sender at this stage.
Why not? If two widgets are connected, they (can) know each other well. The issues with using sender() are similar like in the callback mechanism(store the sender pointer insider recipient).
-
@JonB said in When to use signals and slots, versus direct function calls, from parent to child?:
One important distinction: signals/slots, unlike direct calls, are one way, from signaller to slotter. There is no way to get any information back from the recipient --- no return value, not even a "success/failure". That may make a huge difference in certain cases.
Just to be pedantic: that's not actually the case. If a signal has the same return type as the slot it is connected to, the return value of the slot will be correctly forwarded back to the signal (unless the connection is queued ofc.)
But please do use a lambda instead.
-
@GrecKo said in When to use signals and slots, versus direct function calls, from parent to child?:
If a signal has the same return type as the slot it is connected to, the return value of the slot will be correctly forwarded back to the signal (unless the connection is queued ofc.)
I did not know that! I have always declared my signals
void
, and thought they had to be. Is it documented anywhere?And as we are both saying, signals/slots can be queued, and that is quite different behaviour from when the OP is comparing against direct function calls.
-
@GrecKo said in When to use signals and slots, versus direct function calls, from parent to child?:
Just to be pedantic: that's not actually the case. If a signal has the same return type as the slot it is connected to, the return value of the slot will be correctly forwarded back to the signal (unless the connection is queued ofc.)
I've never seen this before in working code. Proof please ;-)
I'm with @JonB, when I learned about signals it was told (somewhere, I think even in the Qt Documentation) that signals are always declared withvoid
.
(technically void functions that are being caught by MOC when parsing the code to make the connection and "call" the slot/connected function when the signal "function" is called/emitted)@SuhasKrishanamurthy
why does your answer look like it was written by ChatGPT?! ;-)
I'm pretty sure OP could have done that himself if he wanted to ;-) -
@Pl45m4 said in When to use signals and slots, versus direct function calls, from parent to child?:
I've never seen this before in working code. Proof please ;-)
#ifndef SIGNALTEST_H #define SIGNALTEST_H #include <QObject> class SignalTest : public QObject { Q_OBJECT public: explicit SignalTest(QObject *parent = nullptr); public slots: int intSlot() { return 123456; } signals: int intSignal(); }; #endif // SIGNALTEST_H
SignalTest *obj = new SignalTest; QObject::connect(obj, &SignalTest::intSignal, obj, &SignalTest::intSlot, Qt::DirectConnection); qDebug() << /*emit*/ obj->intSignal();
We do indeed get
123456
printed as return value from signal call, as per @GrecKo.I do not think any of the (documented, at least) signals used by Qt have a return value, but it does work. Of course, if I change to
Qt::QueuedConnection
it does not work, I get0
back.Googling, even @SGaist wrote in https://forum.qt.io/post/596362
Signals have no return value.
And in the "other" forum someone wrote in https://www.qtcentre.org/threads/70910-How-to-get-the-return-value-when-signal-emit?p=307681#post307681
All signals and slots have a "void" return value. You cannot return anything that way.
But over at stackoverflow the accepted answer at https://stackoverflow.com/a/5903082/489865 shows same as mine but with a
QString
return and discusses it a bit further.So it seems this is a little known "feature". I do not see the Qt docs saying anything about this, neither that signals should be
void
nor what happens if they return a value. -