Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can Qt signals return a value?

Boost.Signals allows various strategies of using the return values of slots to form the return value of the signal. E.g. adding them, forming a vector out of them, or returning the last one.

The common wisdom (expressed in the Qt documentation [EDIT: as well as some answers to this question ]) is that no such thing is possible with Qt signals.

However, when I run the moc on the following class definition:

class Object : public QObject {     Q_OBJECT public:     explicit Object( QObject * parent=0 )         : QObject( parent ) {}  public Q_SLOTS:     void voidSlot();     int intSlot();  Q_SIGNALS:     void voidSignal();     int intSignal(); }; 

Not only doesn't moc complain about the signal with the non-void return type, it seems to actively implement it in such a way as to allow a return value to pass:

// SIGNAL 1 int Object::intSignal() {     int _t0;     void *_a[] = { const_cast<void*>(reinterpret_cast<const void*>(&_t0)) };     QMetaObject::activate(this, &staticMetaObject, 1, _a);     return _t0; } 

So: according to the docs, this thing isn't possible. Then what is moc doing here?

Slots can have return values, so can we connect a slot with a return value to a signal with a return value now? May that be possible, after all? If so, is it useful?

EDIT: I'm not asking for workarounds, so please don't provide any.

EDIT: It obviously isn't useful in Qt::QueuedConnection mode (neither is the QPrintPreviewWidget API, though, and still it exists and is useful). But what about Qt::DirectConnection and Qt::BlockingQueuedConnection (or Qt::AutoConnection, when it resolves to Qt::DirectConnection).

like image 755
Marc Mutz - mmutz Avatar asked Apr 30 '11 13:04

Marc Mutz - mmutz


People also ask

How do signals work in Qt?

In Qt, we have an alternative to the callback technique: We use signals and slots. A signal is emitted when a particular event occurs. Qt's widgets have many predefined signals, but we can always subclass widgets to add our own signals to them. A slot is a function that is called in response to a particular signal.

Are Qt signals asynchronous?

So in normal cases, it will be synchronous and blocking, and with queued connections it will be asynchronous and non-blocking.

Are Qt signals and slots thread safe?

It is generally unsafe to provide slots in your QThread subclass, unless you protect the member variables with a mutex. On the other hand, you can safely emit signals from your QThread::run() implementation, because signal emission is thread-safe.


2 Answers

OK. So, I did a little more investigating. Seems this is possible. I was able to emit a signal, and receive value from the slot the signal was connected to. But, the problem was that it only returned the last return value from the multiple connected slots:

Here's a simple class definition (main.cpp):

#include <QObject> #include <QDebug>  class TestClass : public QObject {     Q_OBJECT public:     TestClass();  Q_SIGNALS:     QString testSignal();  public Q_SLOTS:     QString testSlot1() {         return QLatin1String("testSlot1");     }     QString testSlot2() {         return QLatin1String("testSlot2");     } };  TestClass::TestClass() {     connect(this, SIGNAL(testSignal()), this, SLOT(testSlot1()));     connect(this, SIGNAL(testSignal()), this, SLOT(testSlot2()));      QString a = emit testSignal();     qDebug() << a; }  int main() {     TestClass a; }  #include "main.moc" 

When main runs, it constructs one of the test classes. The constructor wires up two slots to the testSignal signal, and then emits the signal. It captures the return value from the slot(s) invoked.

Unfortunately, you only get the last return value. If you evaluate the code above, you'll get: "testSlot2", the last return value from the connected slots of the signal.

Here's why. Qt Signals are a syntax sugared interface to the signaling pattern. Slots are the recipients of a signal. In a direct connected signal-slot relationship, you could think of it similar to (pseudo-code):

foreach slot in connectedSlotsForSignal(signal):     value = invoke slot with parameters from signal return value 

Obviously the moc does a little more to help in this process (rudimentary type checking, etc), but this helps paint the picture.

like image 175
jsherer Avatar answered Oct 14 '22 08:10

jsherer


No, they can't.

Boost::signals are quite different from those in Qt. The former provide an advanced callback mechanism, whereas the latter implement the signaling idiom. In the context of multithreading, Qt's (cross-threaded) signals depend on message queues, so they are called asynchronously at some (unknown to the emitter's thread) point in time.

like image 27
vines Avatar answered Oct 14 '22 08:10

vines