web-dev-qa-db-fra.com

Utiliser emit vs appeler un signal comme s'il s'agissait d'une fonction normale dans Qt

Disons que j'ai ce signal:

signals:
    void progressNotification(int progress);

Ce n'est que récemment que j'ai appris le mot-clé emit dans Qt. Jusqu'à présent, j'avais l'habitude d'exécuter des signaux en les appelant simplement comme une fonction normale. Donc au lieu de:

emit progressNotification(1000 * seconds);

Je souhaiterai écrire:

progressNotification(1000 * seconds);

Les appeler comme cela semblait fonctionner, et tous les slots connectés s'exécutaient. L'utilisation du mot-clé emit provoque-t-elle un comportement différent, ou s'agit-il simplement d'un sucre syntaxique?

91
sashoalm

emit n'est qu'un sucre syntaxique. Si vous regardez la sortie pré-traitée de la fonction qui émet un signal, vous verrez que emit est tout simplement parti.

La "magie" se produit dans le code généré pour la fonction d'émission de signal, que vous pouvez consulter en inspectant le code C++ généré par moc.

Par exemple, un signal foo sans paramètres génère cette fonction membre:

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

Et le code emit foo(); est prétraité simplement foo();

emit est défini dans Qt/qobjectdefs.h (de toute façon dans la version open source de la source), comme ceci:

#ifndef QT_NO_EMIT
# define emit
#endif

(La définition de garde vise à vous permettre d’utiliser Qt avec d’autres frameworks ayant des noms en collision via l’option no_keywords QMake config.)

82
Mat

Au bout de 18 mois ... j'ai commencé par commenter sous la réponse de @ Mat et je manquais rapidement de place. Donc la réponse.

IMO emit n'est ni un sucre syntaxique ni un mot clé simple en ce sens que

  1. Il génère du code (comme expliqué par @Mat ci-dessus),
  2. Cela aide le mécanisme connect à reconnaître qu’il s’agit bien d’un signal, et
  3. Cela fait de votre signal une partie d'un système "plus grand", où les signaux et les réponses (slots) peuvent être exécutés de manière synchrone ou asynchrone, ou mis en file d'attente, selon l'endroit et le mode d'émission du signal. C'est une fonctionnalité extrêmement utile du système de signal/slot.

L'ensemble du système de signal/emplacement est un idiome différent d'un simple appel de fonction. Je crois que cela provient du modèle d'observateur. Il y a aussi une différence majeure entre un signal et un slot: un signal n'a pas à implémenter, alors qu'un slot doit être =!

Vous marchez dans la rue et voyez une maison en feu (un signal). Vous composez le 911 (connectez le signal d’incendie au logement de réponse 911). Le signal était niquement émis, alors que l'emplacement était mis en œuvre par le service d'incendie. Peut-être imprécis, mais vous voyez l'idée. Regardons l'exemple de OP.

Certains objets backend savent combien de progrès ont été accomplis. Donc, il pourrait simplement emit progressNotification(...) signaler. Il appartient à la classe qui affiche la barre de progression réelle de capter ce signal et de l'exécuter. Mais comment la vue se connecte-t-elle à ce signal? Bienvenue sur le système de signal/slot de Qt. On peut maintenant concevoir une classe de gestionnaire (généralement un widget de toutes sortes), qui consiste en un objet de vue et un objet de calcul de données (les deux étant QObjects), pouvant exécuter connect (m_myDataEngine, &DataEngine::progressNotification, m_myViewObj, &SimpleView::displayProgress).

N'entrons pas dans les aspects de conception de la classe de gestionnaires, mais disons simplement que c'est là que le système signal/slot brille. Je peux me concentrer sur la conception d'une architecture très propre pour mon application. Pas toujours, mais souvent, je trouve que je simplement émettre des signaux mais implémenter des slots.

S'il est possible d'utiliser/appeler une méthode de signal sans jamais l'émettre, cela implique nécessairement que vous n'avez jamais eu besoin de cette fonction en tant que signal en premier lieu.

3
NameRakes