I segnali Qt possono restituire un valore?

Boost.Signals consente varie strategie di utilizzo dei valori di ritorno degli slot per formare il valore di ritorno del segnale. Ad esempio aggiungendoli, formando un vector da loro o restituendo l’ultimo.

La saggezza comune (espressa nella documentazione Qt [EDIT: così come alcune risposte a questa domanda ] ) è che nessuna cosa del genere è ansible con i segnali Qt.

Tuttavia, quando eseguo il moc sulla seguente definizione di class:

 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 solo Moc si lamenta del segnale con il tipo di ritorno non vuoto, sembra implementarlo triggersmente in modo tale da consentire il passaggio di un valore di ritorno:

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

Quindi: secondo i documenti, questa cosa non è ansible. Allora cosa sta facendo moc qui?

Gli slot possono avere valori di ritorno , quindi possiamo colbind uno slot con un valore di ritorno ad un segnale con un valore di ritorno ora? Potrebbe essere ansible, dopotutto? Se è così, è utile?

EDIT: Non sto chiedendo soluzioni alternative, quindi per favore non fornire alcun.

EDIT: Ovviamente non è utile nella modalità Qt::QueuedConnection (non è nemmeno l’ API QPrintPreviewWidget , eppure esiste ed è utile). Ma che dire di Qt::DirectConnection e Qt::BlockingQueuedConnection (o Qt::AutoConnection , quando si risolve in Qt::DirectConnection ).

OK. Quindi, ho fatto un po ‘più di investigazione. Sembra che questo sia ansible. Sono stato in grado di emettere un segnale e ricevere il valore dallo slot a cui era collegato il segnale. Ma il problema era che restituiva solo l’ultimo valore di ritorno dagli slot multipli connessi:

Ecco una semplice definizione di class ( main.cpp ):

 #include  #include  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" 

Durante le esecuzioni principali, costruisce una delle classi di test. Il costruttore collega due slot al segnale testSignal e quindi emette il segnale. Cattura il valore di ritorno dagli slot invocati.

Sfortunatamente, ottieni solo l'ultimo valore restituito. Se valuti il ​​codice sopra, riceverai: "testSlot2", l'ultimo valore restituito dagli slot connessi del segnale.

Ecco perché. I segnali Qt sono un'interfaccia sintattica per il pattern di segnalazione. Gli slot sono i destinatari di un segnale. In una relazione segnale-slot connessa direttamente, potresti pensare ad essa come (pseudo-codice):

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

Ovviamente il moc fa un po 'di più per aiutare in questo processo (controllo di tipo rudimentale, ecc.), Ma questo aiuta a dipingere l'immagine.

No, non possono.

Boost::signals sono molto diversi da quelli in Qt. I primi forniscono un meccanismo di callback avanzato, mentre i secondi implementano l’idioma di segnalazione. Nel contesto del multithreading, i segnali di Qt (cross-threaded) dipendono dalle code dei messaggi, quindi vengono chiamati in modo asincrono in un punto (sconosciuto al thread dell’emettitore) nel tempo.

La funzione qt_metacall di Qt restituisce un codice di stato intero. Per questo motivo, ritengo che ciò renda imansible un effettivo valore di ritorno (a meno che non ci si diverta con il sistema meta object ei file moc dopo la precompilazione).

Tuttavia, hai a disposizione parametri di funzionamento normali. Dovrebbe essere ansible modificare il codice in modo tale da utilizzare i parametri “out” che fungono da “ritorno”.

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

È ansible ottenere un valore di ritorno dal Qt signal con il seguente codice:

Il mio esempio mostra come usare un Qt signal per leggere il testo di un QLineEdit . Sto solo estendendo ciò che @jordan ha proposto:

Dovrebbe essere ansible modificare il codice in modo tale da utilizzare i parametri “out” che fungono da “ritorno”.

 #include  #include  class SignalsRet : public QObject { Q_OBJECT public: SignalsRet() { connect(this, SIGNAL(Get(QString*)), SLOT(GetCurrentThread(QString*)), Qt::DirectConnection); connect(this, SIGNAL(GetFromAnotherThread(QString*)), SLOT(ReadObject(QString*)), Qt::BlockingQueuedConnection); edit.setText("This is a test"); } public slots: QString call() { QString text; emit Get(&text); return text; } signals: void Get(QString *value); void GetFromAnotherThread(QString *value); private slots: void GetCurrentThread(QString *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(QString *value) { QString text = edit.text(); *value = text; } private: QLineEdit edit; }; 

Per usare questo, basta call(); .

Puoi provare a risolvere questo problema con il seguente:

  1. Tutti i tuoi slot collegati devono salvare i loro risultati in qualche luogo (contenitore) accessibile dall’object di segnalazione
  2. L’ultimo slot connesso dovrebbe in qualche modo (selezionare il valore massimo o l’ultimo valore) elaborare i valori raccolti ed esporre l’unico
  3. L’object emittente può provare ad accedere a questo risultato

Proprio come un’idea.