web-dev-qa-db-de.com

Verwenden von emit oder Aufrufen eines Signals, als wäre es eine reguläre Funktion in Qt

Nehmen wir an, ich habe dieses Signal:

signals:
    void progressNotification(int progress);

Das Schlüsselwort emit habe ich erst kürzlich in Qt kennengelernt. Bisher habe ich Signale ausgeführt, indem ich sie wie eine normale Funktion aufrief. Also statt:

emit progressNotification(1000 * seconds);

Ich würde schreiben:

progressNotification(1000 * seconds);

Ein solcher Aufruf schien zu funktionieren, und alle verbundenen Slots wurden ausgeführt. Verursacht die Verwendung des Schlüsselworts emit ein anderes Verhalten, oder handelt es sich nur um syntaktischen Zucker?

91
sashoalm

emit ist nur syntaktischer Zucker. Wenn Sie sich die vorverarbeitete Ausgabe der Funktion ansehen, die ein Signal ausgibt, sehen Sie, dass emit einfach weg ist.

Die "Magie" findet in dem generierten Code für die Signalaussendefunktion statt, die Sie anzeigen können, indem Sie den von moc generierten C++ - Code überprüfen.

Zum Beispiel erzeugt ein foo Signal ohne Parameter diese Mitgliedsfunktion:

void W::foo()
{
    QMetaObject::activate(this, &staticMetaObject, 0, 0);
}

Und der Code emit foo(); wird vorverarbeitet, um einfach foo();

emit wird in Qt/qobjectdefs.h (in der Open-Source-Variante der Quelle) wie folgt definiert:

#ifndef QT_NO_EMIT
# define emit
#endif

(Mit dem Define Guard können Sie Qt mit anderen Frameworks verwenden, deren Namen über die QMake-Konfigurationsoption no_keywords Kollidieren.)

82
Mat

Nach 18 Monaten ... begann ich mit Kommentaren unter der Antwort von @ Mat und es ging mir schnell der Raum aus. So lautet die Antwort.

IMO emit ist weder syntaktischer Zucker noch ein einfaches Schlüsselwort in diesem Sinne

  1. Es generiert Code (wie oben von @Mat erklärt),
  2. Es hilft dem connect Mechanismus zu erkennen, dass es sich tatsächlich um ein signal handelt, und
  3. Dadurch wird Ihr Signal Teil eines "größeren" Systems, in dem Signale und Antworten (Slots) synchron oder asynchron ausgeführt oder in eine Warteschlange gestellt werden können, je nachdem, wo und wie das Signal ausgegeben wurde. Dies ist eine äußerst nützliche Funktion des Signal/Slot-Systems.

Das gesamte Signal/Slot-System unterscheidet sich von einem einfachen Funktionsaufruf. Ich glaube, dass es vom Beobachtermuster herrührt. Es gibt auch einen großen Unterschied zwischen einem signal und einem slot: Ein Signal muss nicht implementiert werden, während ein Slot muss implementiert werden =!

Sie gehen die Straße entlang und sehen ein brennendes Haus (ein Signal). Sie wählen 911 (verbinden Sie das Feuersignal mit dem 911-Antwortslot). Das Signal war nur gesendet, während der Steckplatz wurde implementiert von der Feuerwehr. Mag ungenau sein, aber Sie bekommen die Idee. Schauen wir uns das Beispiel von OP an.

Ein Backend-Objekt weiß, wie viel Fortschritt gemacht wurde. Es könnte also einfach emit progressNotification(...) signalisieren. Es liegt an der Klasse, die den aktuellen Fortschrittsbalken anzeigt, dieses Signal aufzunehmen und darauf auszuführen. Aber wie verbindet sich die Ansicht mit diesem Signal? Willkommen beim Qt Signal/Slot System. Man kann sich jetzt eine Manager-Klasse vorstellen (typischerweise eine Art Widget), die aus einem Ansichtsobjekt und einem Datenberechnungsobjekt besteht (beide sind QObjects) und connect (m_myDataEngine, &DataEngine::progressNotification, m_myViewObj, &SimpleView::displayProgress) ausführen kann.

Kommen wir nicht zu den Designaspekten der Managerklasse, sondern sagen wir nur, dass hier das Signal/Slot-System glänzt. Ich kann mich darauf konzentrieren, eine sehr saubere Architektur für meine Anwendung zu entwerfen. Nicht immer, aber oft stelle ich fest, dass ich nur Signale aussende, aber Slots implementiere.

Wenn es möglich ist, eine Signalmethode zu verwenden/aufzurufen ohne sie jemals auszustrahlen, impliziert dies notwendigerweise, dass Sie haben diese Funktion nie als Signal benötigt an erster Stelle steht.

3
NameRakes