Mise en œuvre avec Visual Basic
5. Les événements
Cette erreur intervient au moment de l’appel de la procédure de tri. Les éléments du tableau que nous avons passé comme paramètre n’implémentent pas l’interface Comparable et nous ne sommes pas certains qu’ils contiennent une fonction compare. À noter que, même s’il existe une fonction compare correcte dans la classe voiture, il faut obligatoirement spécifier que cette classe implémente l’interface Comparable, pour que notre code puisse fonctionner.
5. Les événements
Les méthodes nous permettent de communiquer avec les objets qui composent une application mais les objets ont également la possibilité de nous faire part de leurs réactions en générant des événements. Ces événements doivent ensuite être pris en compte pour réagir à ce qui vient de se passer dans l’application.
Les événements sont très largement utilisés dans la conception de l’interface graphique d’une application car ils nous permettent d’avoir des informations sur les actions effectués par l’utilisateur de l’application.
a. Déclaration et déclenchement d’événements
Voyons, tout d’abord, comment générer un événement dans une classe. La première chose à faire est de déclarer l’événement dans la classe. Cette déclaration s’effectue de la même manière que celle des variables internes à la classe. On utilise pour cela le mot clé event suivi du nom de l’événement. Nous pouvons également, lors de la déclaration, spécifier des paramètres qui fourniront des informations supplémentaires sur l’événement luimême ou sur l’état de l’objet, au moment où l’événement se déclenche. Nous pouvons, par exemple créer dans notre classe Client un événement qui se déclenchera à chaque ajout d’une nouvelle commande. Comme information supplémentaire, notre événement fournira le nombre de commandes après l’ajout.
Public Event NouvelleCommande(ByVal nbCommandes As integer)
Il nous reste maintenant à définir dans quelles conditions notre événement sera déclenché et bien sûr à le déclencher à ce momentlà. Pour notre classe Client, le plus évident est de générer notre événement au moment où l’on exécute la méthode permettant d’ajouter une commande. Pour cela, nous allons créer la méthode AjoutCommande. Cette méthode reçoit comme paramètre le numéro de la commande à ajouter. La seule action de cette méthode sera d’incrémenter le nombre de commandes du client.
Public Sub AjoutCommande(ByVal numero As Integer) nbCommandes = nbCommandes + 1
End Sub
Dans la méthode AjoutCommande, nous allons donc déclencher l’événement avec l’instructionRaiseEvent suivie du nom de l’événement déclaré au préalable dans la classe. Nous devons également fournir les éventuels paramètres déclarés avec notre événement.
Public Sub AjoutCommande(ByVal numero As Integer) nbCommandes = nbCommandes + 1
RaiseEvent NouvelleCommande(nbCommandes) End Sub
Après l’exécution de l’instruction RaiseEvent, l’événement sera transmis à tous les éléments qui se seront déclarés
intéressés par cet événement. Si plusieurs éléments sont intéressés par l’événement, ils recevront les uns après les autres la notification de l’événement.
À noter toutefois qu’il n’est pas possible de prédire l’ordre dans lequel les éléments de notre application seront prévenus, ni de prévenir un nouvel élément tant que le précédent n’aura pas fini de traiter l’événement.
b. Gérer les événements
Regardons maintenant comment récupérer les événements dans notre application. Deux solutions sont possibles :
● déclarer une variable avec le mot clé WithEvents et utiliser la clause Handles.
● Ajouter manuellement un gestionnaire d’événement.
La deuxième solution est plus souple car elle nous permettra d’ajouter ou de supprimer dynamiquement des gestionnaires d’événement pendant le fonctionnement de notre application, mais elle nécessite un peu plus de code que la première solution.
Cette solution nécessite une déclaration de variable spécifique. La déclaration d’une variable pouvant référencer une instance de la classe Client s’effectue de la manière suivante.
Dim WithEvents unClient As Client
Il convient maintenant de décider quel code sera exécuté lorsque cet événement se produira. Une procédure liée à la réception de cet événement doit être créée. Pour cela, l’environnement de développement nous facilite la tâche. En haut de notre fenêtre de code, nous avons deux listes disponibles.
La première nous indique toutes les sources d’événements disponibles et nous permet donc de choisir d’où proviendra notre événement.
La seconde indique, pour la source d’événement actuellement sélectionnée, quels sont les événements susceptibles d’être déclenchés.
Après avoir fait notre choix dans les deux listes, l’environnement génère automatiquement le squelette de la procédure qui sera appelée par le déclenchement de l’événement.
Private Sub unClient_NouvelleCommande(ByVal nbCommandes As Integer) Handles unClient.NouvelleCommande
End Sub
Cette méthode est identique à celles que l’on a écrit jusqu’à présent, avec en plus le mot clé Handles suivi du nom de l’événement qui sera traité par cette procédure. Par convention, le nom de la procédure est constitué par le nom de l’élément suivi par le nom de l’événement géré sur cet objet. Mais ceci reste une convention permettant de faciliter la lecture du code. La seule obligation est que la procédure respecte la signature définie dans l’événement.
Nous pouvons également ajouter plusieurs procédures qui seront appelées par le même événement, mais il faut dans ce cas reprendre le code manuellement et bien sûr utiliser des noms différents pour les procédures. Cette méthode manque de souplesse car il est impossible de choisir, pendant l’exécution, quel gestionnaire d’événement sera utilisé.
Utilisation de la clause Handles
Il existe également une autre contrainte liée au fait que les variables déclarées WithEvents doivent obligatoirement être déclarées en dehors de toute procédure ou fonction.
Pour éviter ces limitations, nous avons la possibilité d’ajouter manuellement des gestionnaires d’événement. Dans ce cas, la variable doit être déclarée sans le mot clé WithEvents. On utilise ensuite le mot cléAddHandler pour associer à un événement une procédure pour le gérer.
AddHandler unClient.NouvelleCommande, AddressOf unClient_NouvelleCommande
Le premier paramètre de AddHandler est l’événement que l’on veut gérer puis on lui indique également, par l’intermédiaire de AddressOf, l’emplacement où se trouve la procédure qui sera exécutée pour gérer cet événement.
Nous pouvons ainsi décider, au cours du fonctionnement de l’application, qui gèrera un événement particulier. Par exemple, si nous avons une application qui fonctionne en mode console ou en mode Windows, nous aurons un mode
AddHandler unClient.NouvelleCommande, AddressOf gestion_graph Else
AddHandler unClient.NouvelleCommande, AddressOf gestion_texte End If
unClient.AjoutCommande(10)
Public Sub gestion_graph(ByVal nbcmd As Integer) MsgBox("nombre de commandes " & nbcmd) End Sub
Public Sub gestion_texte(ByVal nbcmd As Integer) Console.WriteLine(“nombre de commandes " & nbcmd) End Sub
De la même manière, nous pouvons supprimer un gestionnaire d’événement qui est déjà référencé, en utilisantRemoveHandler.
RemoveHandler unClient.NouvelleCommande, AddressOf gestion_graph
Cette instruction ne supprime pas la procédure gestion_graph mais coupe simplement la liaison avec l’événement leChef.augmentation_salaire. Cette liaison pourra être rétablie par la suite en utilisant à nouveau AddHandler.
Dernier point à éclaircir : comment vont se comporter les événements lorsque notre classe sera sousclassée.
Les événements suivent les mêmes règles d’héritage que les propriétés et méthodes. Un événement déclaré dans une classe sera accessible dans toutes ces sousclasses. Une petite restriction existe quand même, puisque le déclenchement de l’événement pourra n’avoir lieu que dans la classe dans laquelle il est déclaré. Pour contourner le problème, il suffit de déclarer une méthode protected dans la classe et simplement faire déclencher l’événement par cette méthode. Nous aurons ensuite la possibilité de déclencher l’événement dans n’importe quelle autre sousclasse, non pas en utilisant directement le RaiseEvent, mais en utilisant la méthode protégée qui le fera pour nous.
Par exemple, pour pouvoir déclencher l’événement dans une sousclasse de Client nous pourrions écrire le code suivant :
Dans la classe Client:
Protected Sub declenche_NouvelleCommande(ByVal nb as integer) RaiseEvent NouvelleCommande (nb)
End sub
Dans la sousclasse de Client: Public Sub plusUne()
...
declenche_NouvelleCommande(numero) ...
End Sub
Ajout et suppression de gestionnaire d’événement
Événements et héritage