Table des matières du kit d'application | Index du kit d'application |
Le kit d'application fournit un système de messagerie qui permet à votre application d'envoyer et recevoir des messages à d'autres applications (y compris aux serveurs et aux applications définis par Be), et à d'autres threads dans votre propre application.
Les principales classes de messagerie sont les suivantes :
Les autres classes de messagerie sont :
Le reste de ce chapitre traite ...
Il décrit comment les classes s'accordent les unes aux autres dans le système de messagerie et met l'accent sur ce que vous pouvez faire dans votre application pour y participer.
Prises dans leur ensemble, les quatre classes fondamentales de messagerie comprennent un gros morceau d'API. Heureusement, la partie essentielle de cette API est assez petite ; c'est ce que nous allons voir maintenant.
Dans la classe BMessage, on trouve un membre de données essentiel, et deux fonctions principales :
/* Les paramètres sont : nom, index, valeur (retournée par référence) */ bool returnValue; aMessage.FindBool("IsEnabled", 2, &returnValue);
En résumé, un BMessage contient (1) une constante commande et (2) un ensemble de champs de données. Chaque BMessage utilisé dans le système de messagerie doit avoir une constante commande, mais tous les objets n'ont pas besoin de champs de données. (D'autres parties de BeOS utilisent des BMessages uniquement pour leurs données. L'objet BClipboard (presse-papiers), par exemple, se moque de la constante commande d'un BMessage.)
|
Remarquez qu'un BMessage ne sait pas comment s'émettre lui-même. Toutefois, comme nous verrons plus tard, il sait comment répondre à son émetteur une fois qu'il se trouve entre les mains du destinataire.
Le rôle de BLooper est de recevoir des messages et de déterminer quoi en faire. Ce travail se divise en quatre activités, prises en charge par les fonctions suivantes :
/* Cette forme de constructeur de BMessage affecte la constante commande. */ be_app->PostMessage(new BMessage(YOUR_CONSTANT_HERE))
Dans les kits Be, les classes BApplication et BWindow héritent de BLooper.
Les objets BHandler sont appelés pour prendre en charge les messages qu'un BLooper reçoit. Un BHandler repose sur deux fonctions principales :
void MyHandler::MessageReceived(BMessage *message) { /* Examen de la constante commande. */ switch ( message->what ) { case YOUR_CONSTANT_HERE: /* Appel d'une fonction traitant ce type de message. */ HandlerFunctionA(); break; case ANOTHER_CONSTANT_HERE: /* idem */ HandlerFunctionB(); break; default: /* Les messages que votre classe n'identifie pas doivent être passés * à la classe de base. */ baseClass::MessageReceived(message); break; } }
BLooper hérite de BHandler, et s'ajoute automatiquement lui-même à sa propre chaîne de gestionnaires. Ce qui signifie qu'un BLooper peut traiter les messages qu'il reçoit — c'est le fonctionnement par défaut pour la plupart des messages. Nous examinerons ce point en profondeur plus loin dans ce chapitre.
Les autres classes héritant de BHandler sont BView et BShelf (toutes deux dans le kit d'interface).
La caractéristique la plus importante de BMessenger est de pouvoir envoyer un message à une application distante. Deux étapes sont nécessaires pour réaliser cela, ce qui met en évidence les caractéristiques principales de la classe :
Les BMessengers peuvent aussi être utiliser pour cibler des paires locales de looper/handler.
Un BLooper extrait un message de sa file d'attente des messages et, via sa fonction DispatchMessage(), distribue le message en invoquant une fonction de BHandler. Mais (1) quel BHandler et (2) quelle fonction ?
Répondons en premier à la question "quel Handler ?". Pour déterminer quel BHandler doit traiter le message arrivant, un BLooper suit les étapes suivantes :
1. Est-ce-que le BMessage cible un BHandler spécifique ? Les deux fonctions BLooper::PostMessage() et BMessenger::SendMessage() fournissent des paramètres additionnels vous permettant de préciser un handler cible que vous souhaitez voir traiter le message (vous pouvez aussi indiquer la cible dans le constructeur du BMessenger). Si un BHandler est spécifié, le BMessage apparaitra dans la fonction MessageReceived() de cet objet (ou il invoquera une fonction de connexion basée sur le message, comme expliqué plus bas).
2. Est-ce-que le BLooper indique un handler préféré ? Via sa fonction SetPreferredHandler(), un BLooper peut désigner un des objets de sa chaîne de gestionnaires comme son gestionnaire préféré, et passer tous les messages à cet objet.
3. Le BLooper traite le BMessage lui-même. S'il n'y a ni handler cible ni gestionnaire préféré, le BLooper traite le message lui-même — en d'autres mots, le message est passé à la propre fonction MessageReceived() du BLooper (ou fonction de connexion basée sur le message).
Nous devons mentionner ici que toutes deux, BApplication et la classe BWindow, affinent un peu le processus de décision. Toutefois, leur apport s'applique uniquement aux messages système (décrits plus bas). Les messages définis par vous mêmes (c.a.d. les constantes commande définies par votre application) respectent toujours les modalités de distribution des messages décrites ici.
|
Comme décrit plus haut, un BLooper passe un BMessage à un BHandler en invoquant la fonction MessageReceived() de ce dernier. C'est vrai pour tous les messages que vous créez, mais ça ne l'est pas de certains messages définis et émis par le système. Ces messages produits par le système (ou messages système) — en particulier ceux qui rendent compte d'évènement utilisateur comme B_MOUSE_DOWN ou B_APP_ACTIVATED — invoquent des fonctions de connexion spécifiques.
Par exemple, quand l'utilisateur presse une touche, un message B_KEY_DOWN est émis vers l'objet BWindow actif.. Via sa fonction DispatchMessage(), BWindow invoque la fonction MouseDown() du BView qui possède à ce moment le focus clavier. (Quand un BView est fait le centre (focus) des évènements clavier, sa fenêtre le promeut au rang de gestionnaire préféré.)
Donc, répondre à la question "quelle fonction" est assez simple : Si le BMessage est un message système désigné pour une fonction de connexion, la fonction de connexion est invoquée. S'il n'est pas désigné pour une fonction de connexion, la fonction MessageReceived() de BHandler est invoquée.
La liste complète des messages système et des fonctions de connexion correspondantes est donnée dans l'Annexe des messages système. Notez que les messages système ne sont pas tous désignés pour des fonctions de connexion ; certains apparaissent dans MessageReceived().
Jetons de nouveau un oeil à MessageReceived(). Il a été affirmé, dans le squelette de code montré plus haut, qu'une mise en oeuvre typique de MessageReceived() devait inclure une invocation à la version de la classe de base de la fonction :
void MyHandler::MessageReceived(BMessage *message) { switch ( message->what ) { /* Les constantes commande que vous gérez sont ici. */ default: /* Les messages que votre classe ne reconnait pas doivent * être passés à la classe de base class. */ baseClass::MessageReceived(message); break; } }
Ce n'est pas seulement une bonne idée — c'est une part essentielle du système de messagerie. Faire suivre le message à la classe de base produit deux effets : laisser les messages (1) remonter la hiérarchie des classes, et (2) passer par la chaîne de gestionnaires (dans cet ordre).
Remonter la hiérarchie des classes est sans surprise - Ce n'est pas plus différent pour la fonction MessageReceived() que ça l'est pour n'importe quelle autre fonction. Mais au sommet de la hiérarchie — pour la classe BHandler elle-même — on a une petite variante. La mise en oeuvre de BHandler MessageReceived() recherche le gestionnaire suivant dans la chaîne de gestionnaires de BLooper et invoque la fonction MessageReceived() de cet objet.
Il existe deux fonctions qui envoient des messages à des destinataires distincts :
Vous pouvez poster un message si le BLooper destinataire est dans votre application :
myLooper->PostMessage(new BMessage(DO_SOMETHING), targetHandler);
Comme montré ici, vous pouvez spécifier le handler que vous voulez voir traiter le message posté. La seule contrainte est que le BHandler appartienne au BLooper.
Si le paramètre handler vaut NULL, le message est traité par le gestionnaire préféré du looper.
myLooper->PostMessage(new BMessage(DO_SOMETHING), NULL);
En utilisant le gestionnaire par défaut, vous laissez le looper décider qui doit traiter le message.
|
Si vous voulez envoyer un message à une autre application, il faut utiliser la fonction SendMessage() de BMessenger. Vous construisez en premier un objet BMessenger qui identifie l'application distante par signature...
BMessenger messenger("application/x-some-app");
...et ensuite vous invoquez SendMessage():
messenger.SendMessage(new BMessage(DO_SOMETHING));
|
Chaque BMessage que vous envoyez identifie l'application qui l'a émis. Le destinataire du message peut répondre au message que vous (l'émetteur) attendiez une réponse ou non. Par défaut, les messages de réponse sont traités par votre objet BApplication. Si vous voulez que les messages de réponse soient traités par un autre BHandler, vous spécifiez l'objet en paramètre final de l'appel à PostMesssage() ou SendMessage() :
myLooper->PostMessage(new BMessage(DO_SOMETHING), targetHandler, replyHandler); /* ou */ myMessenger.SendMessage(&message, replyHandler);
La réponse est envoyée de manière asynchrone en ce qui concerne la fonction PostMessage() / SendMessage().
SendMessage() (uniquement) vous permet de demander un message de réponse, retourné de manière synchrone dans l'appel à SendMessage() call lui-même :
BMessage reply; myMessenger.SendMessage(&message, &reply);
SendMessage() n'effectue pas son retour tant qu'une réponse n'est pas reçue. Un message par défaut est créé et renvoyé si le destinataire ne répond pas assez vite.
La fonction SendReply() de BMessage possède la même syntaxe que SendMessage(), donc il est possible de demander une réponse synchrone à un message qui est lui-même une réponse,
BMessage message(READY); BMessage reply; theMessage->SendReply(&message, &reply); if ( reply->what != B_NO_REPLY ) { . . . }
ou de désigner un BHandler pour une réponse asynchrone à la réponse :
theMessage->SendReply(&message, someHandler);
De cette manière, deux applications peuvent établir un échange constant de messages.
Pour être notifié d'un message arrivant, un BHandler doit "appartenir" au BLooper ; il doit avoir été ajouté à la liste des gestionnaires éligibles du BLooper. La liste peut contenir n'importe quel nombre d'objets, mais à un instant donné un BHandler ne peut appartenir qu'à un seul BLooper.
Les gestionnaires appartenant au même BLooper peuvent être liés dans une liste chaînée. Si un objet ne peut répondre à un message, le système passe le message au gestionnaire suivant.
La fonction AddHandler() de BLooper effectue l'association looper-handler ; la fonction SetNextHandler() de BHandler établit la chaîne handler-handler.
La classe BMessageFilter permet de créer des fonctions filtres qui examinent et re-routent (ou rejettent) les messages arrivants avant qu'ils soient traités par un BLooper. Les filtres de messages peuvent également être appliqués aux objets individuels BHandler.
Source et destination d'un message doivent tous deux s'accorder sur son format — la constante commande, les noms et types des champs de données. Elles doivent aussi être d'accord sur les détails de l'échange — quand le message peut être émis, s'il requiert une réponse, que doit être le format de la réponse, que faire quand un élément de données attendu est absent, etc.
Rien de ceci n'est un problème quand les messages sont seulement utilisés à l'intérieur d'une application ; le développeur de l'application peut s'occuper de ces détails. Toutefois, les protocoles des messages inter-applications doivent être publiés. Il vous est instamment demandé de rendre public les spécifications de tous les messages que votre application est désireuse d'accepter de sources externes et de tous ceux qu'elle peut définir pour être délivrés à d'autres applications.
Table des matières du kit d'application | Index du kit d'application |
Copyright © 2000 Be, Inc. All rights reserved..