Les signaux Qt peuvent-ils renvoyer une valeur?

Boost.Signals permet différentes stratégies d’utilisation des valeurs de retour des slots pour former la valeur de retour du signal. Par exemple, en les ajoutant, en formant un vector ou en renvoyant le dernier.

La sagesse commune (exprimée dans la documentation de Qt [EDIT: ainsi que certaines réponses à cette question ] ) est qu’une telle chose n’est pas possible avec les signaux Qt.

Cependant, lorsque je lance le moc sur la définition de classe suivante:

 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(); }; 

Non seulement moc ne se plaint pas du signal avec le type de retour non-vide, il semble l’implémenter activement de manière à laisser passer une valeur de retour:

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

Donc, selon les documents, cette chose n’est pas possible. Alors que fait moc ici?

Les slots peuvent avoir des valeurs de retour , alors pouvons-nous connecter un slot avec une valeur de retour à un signal avec une valeur de retour maintenant? Est-ce possible, après tout? Si oui, est-ce utile?

EDIT: Je ne demande pas de solutions de contournement, veuillez ne pas en fournir.

EDIT: Ce n’est évidemment pas utile en mode Qt::QueuedConnection (l’ API QPrintPreviewWidget n’est pas non plus, et pourtant elle existe et est utile). Mais qu’en est-il de Qt::DirectConnection et Qt::BlockingQueuedConnection (ou Qt::AutoConnection , quand il est résolu en Qt::DirectConnection ).

D’ACCORD. Donc, j’ai fait un peu plus d’investigations. Cela semble possible. J’ai pu émettre un signal et recevoir une valeur de la fente à laquelle le signal était connecté. Mais, le problème était qu’il ne renvoyait que la dernière valeur de retour des multiples slots connectés:

Voici une définition de classe simple ( main.cpp ):

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

Lors de l'exécution principale, il construit l'une des classes de test. Le constructeur connecte deux signaux au signal testSignal, puis émet le signal. Il capture la valeur de retour du ou des logements invoqués.

Malheureusement, vous n'obtenez que la dernière valeur de retour. Si vous évaluez le code ci-dessus, vous obtiendrez: "testSlot2", la dernière valeur renvoyée par les slots connectés du signal.

Voici pourquoi. Les signaux Qt sont une interface syntaxique sucrée au modèle de signalisation. Les slots sont les destinataires d'un signal. Dans une relation signal-slot connectée directe, vous pourriez penser à ceci (pseudo-code):

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

De toute évidence, le moc fait un peu plus pour aider dans ce processus (vérification de type rudimentaire, etc.), mais cela aide à peindre l'image.

Non, ils ne peuvent pas.

Boost::signals sont très différents de ceux de Qt. Les premiers fournissent un mécanisme de rappel avancé, tandis que les seconds implémentent le langage de signalisation. Dans le contexte du multithreading, les signaux de Qt (cross-threaded) dépendent des files de messages, ils sont donc appelés de manière asynchrone à un moment donné (inconnu du thread de l’émetteur).

La fonction qt_metacall de Qt renvoie un code d’état entier. Pour cette raison, je crois que cela rend une valeur de retour impossible (à moins que vous ne trafiquiez avec le système d’object méta et les fichiers moc après la précompilation).

Vous disposez toutefois de parameters de fonction normaux. Il devrait être possible de modifier votre code de manière à utiliser des parameters “out” qui agissent comme votre “retour”.

 void ClassObj::method(return_type * return_) { ... if(return_) *return_ = ...; } // somewhere else in the code... return_type ret; emit this->method(&ret); 

Vous pouvez obtenir une valeur de retour du Qt signal avec le code suivant:

Mon exemple montre comment utiliser un Qt signal pour lire le texte d’un QLineEdit . Je ne fais que prolonger ce que @jordan a proposé:

Il devrait être possible de modifier votre code de manière à utiliser des parameters “out” qui agissent comme votre “retour”.

 #include  #include  class SignalsRet : public QObject { Q_OBJECT public: SignalsRet() { connect(this, SIGNAL(Get(QSsortingng*)), SLOT(GetCurrentThread(QSsortingng*)), Qt::DirectConnection); connect(this, SIGNAL(GetFromAnotherThread(QSsortingng*)), SLOT(ReadObject(QSsortingng*)), Qt::BlockingQueuedConnection); edit.setText("This is a test"); } public slots: QSsortingng call() { QSsortingng text; emit Get(&text); return text; } signals: void Get(QSsortingng *value); void GetFromAnotherThread(QSsortingng *value); private slots: void GetCurrentThread(QSsortingng *value) { QThread *thread = QThread::currentThread(); QThread *mainthread = this->thread(); if(thread == mainthread) //Signal called from the same thread that SignalsRet class was living ReadObject(value); else //Signal called from another thread emit GetFromAnotherThread(value); } void ReadObject(QSsortingng *value) { QSsortingng text = edit.text(); *value = text; } private: QLineEdit edit; }; 

Pour l’utiliser, il suffit de demander un call(); .

Vous pouvez essayer de résoudre ce problème avec les éléments suivants:

  1. Tous vos slots connectés doivent enregistrer leurs résultats à un endroit (conteneur) accessible depuis l’object de signalisation
  2. Le dernier connecteur connecté doit sélectionner (max ou last value) traiter les valeurs collectées et exposer le seul
  3. L’object émetteur peut essayer d’accéder à ce résultat

Juste comme une idée.