IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Création et utilisation de classes personnalisées en VB 6.0 et VBA (partie 1)

Date de publication : 15/04/2008

Par Pierre Fauconnier (Mon site sur www.developpez.com)
 

Grâce aux classes personnalisées, créez vos propres objets, maintenez facilement votre code, réutilisez rapidement votre code dans de nouvelles applications

I. Introduction
I-A. Pourquoi utiliser des classes personnalisées
I-B. Objectifs
I-C. Notions abordées dans la partie 1
I-D. Notions abordées dans la partie 2
I-E. Notions abordées dans la partie 3
I-F. Prérequis
II. Notions d'objet
II-A. Les objets de la vie courante
II-B. Les objets informatiques
II-B-1. Quelques objets informatiques
II-B-2. L'explorateur d'objets en VB et VBA
III. Utilisation de variables simples, puis d'un "pseudo-objet", le type personnalisé
III-A. Manipulation des données d'un contact sans utilisation d'un type personnalisé
III-A-1. Limites de l'utilisation de variables simples
III-B. Qu'est-ce qu'une variable de type personnalisé et quand créer un type personnalisé?
III-C. Création d'un type personnalisé
III-D. Utilisation de mon type personnalisé
III-E. Différences entre l'utilisation de variables et l'utilisation d'un type personnalisé
III-F. Limites de l'utilisation d'un type personnalisé
IV. Une classe pour gérer des contacts
IV-A. Notion de classe,notion d'objet, notion d'encapsulation
IV-A-1. Notion de classe
IV-A-2. Notion d'objet
IV-A-3. Notion d'encapsulation
IV-B. Création de notre première classe
IV-B-1. Module de classe
IV-B-1-a. Ajout d'un module de classe en VB 6.0
IV-B-1-b. Ajout d'un module de classe en VBA
IV-B-2. Création de propriétés simples pour notre classe
IV-B-3. Utilisation de notre classe au sein d'un code
IV-B-4. Conclusions
IV-C. Création de vraies propriétés
IV-C-1. Notions de propriétés en lecture/écriture, en lecture seule et en écriture seule
IV-C-2. Propriétés en lecture/écriture
IV-C-3. Propriétés en lecture seule
IV-C-4. Propriétés en écriture seule
IV-C-5. Propriétés en lecture/écriture qui basculent en lecture seule
IV-C-6. Utilisation de Property Get et Property Let
IV-C-6-a. La propriété "Nom" en lecture-écriture
IV-C-6-a-i. Fonctionnement du code
IV-C-6-a-ii. Contrôle de la saisie du nom en vue de sa modification
IV-C-6-a-iii. Adaptation du code: Transformation des variables en propriétés
IV-C-6-a-iv. La propriété "Age" en lecture seule
IV-C-6-a-v. Un petit mot sur l'explorateur d'objets
IV-C-6-a-vi. Conclusions
IV-D. Déclenchement d'erreurs au sein de notre classe
IV-D-1. Génération d'une erreur au sein de la classe
IV-E. Mettre des évènements à disposition du code appelant
IV-E-1. Exemples d'évènements mis à disposition par des classes d'objets
IV-E-2. Création d'un évènement pour notre classe personnalisée
IV-E-2-a. Création et gestion d'un évènement sans paramètre
IV-E-2-a-i. Création de l'évènement
IV-E-2-a-ii. Gestion de l'évènement dans le code appelant
IV-E-2-b. Création d'un évènement qui passe un paramètre au code appelant
IV-E-2-b-i. Exemples d'évènements avec paramètre(s)
IV-E-2-b-ii. Création de l'évènement au sein de la classe
IV-E-2-b-iii. Utilisation de l'évènement et de son paramètre dans le code appelant
IV-E-2-c. Modification du déroulement du code dans la classe grâce à un paramètre "décisionnel"
IV-E-2-c-i. Création d'un paramètre décisionnel
IV-E-2-c-ii. Gestion de l'évènement dans le code appelant
V. Conclusions
VI. Remerciements


I. Introduction


I-A. Pourquoi utiliser des classes personnalisées

On est souvent confronté, lors de l'utilisation de VB ou de VBA, au problème de "réinventer la roue" à chaque nouveau travail que l'on développe.

Si je prends l'exemple d'applications liées à la gestion d'une entreprise, nombre de nos classeurs Excel, de nos bases de données Access, voire de nos applications VB, gèrent les données de contacts.

L'utilisation de classes personnalisées va permettre un gain de temps appréciable en favorisant la réutilisation et la maintenance du code. De plus, les classes personnalisées permettent la mise à disposition d'objets complexes à des programmeurs qui pourront "se borner" à utiliser les propriétés et méthodes qu'une classe personnalisée met à leur disposition.


I-B. Objectifs

Ce tutoriel en trois parties a pour ambition de vous expliquer le fonctionnement des classes personnalisées en VB 6.0 ou en VBA, de vous démontrer que la mise au point de classes performantes n'est pas un travail impossible, et de vous prouver que les classes personnalisées permettent la mise à disposition d'autres programmeurs d'un code qui les soulage de la "réinvention de la roue".


I-C. Notions abordées dans la partie 1

Dans cette partie, nous allons manipuler principalement les concepts liés aux propriétés d'un objet.

Pour cela, nous allons créer ce que l'on appelle une "classe métier", c'est-à-dire une classe qui reproduit en informatique un objet manipulé

Notions abordées dans la partie 1
  • Qu'est-ce qu'un objet informatique
  • Qu'est-ce qu'une propriété
  • Propriété en lecture seule, en écriture seule, en lecture écriture
  • Encapsulation
  • Génération des erreurs dans une classe et gestion par le code appelant
  • Génération des évènements et gestion par le code appelant

I-D. Notions abordées dans la partie 2

Dans un deuxième temps, nous utiliserons notre classe "métier" vue en partie 1 en la liant à différentes sources de données au travers d'une nouvelle classe d'accès aux données.

Notions abordées dans la partie 2
  • Création d'un objet personnalisé au travers d'une classe d'accès aux données
  • Liaison d'un objet personnalisé à une source pour la lecture des données
  • Liaison d'un objet personnalisé à une source pour la modification des données du fichier source
  • Portabilité du jeu des classes
  • Utilisation de données d'une base Access dans un fichier Excel grâce aux classes personnalisées

I-E. Notions abordées dans la partie 3

La troisième partie nous permettra d'aborder une classe liant propriétés, fonctions et méthodes.


I-F. Prérequis

L'utilisation et la compréhension de ce cours requiert une bonne connaissance de base en VB ou VBA.
Vous devez notamment savoir déclarer et utiliser des variables et comprendre la notion de portée d'utilisation d'une variable.
Vous devez savoir déclarer et utiliser des fonctions personnalisées et des procédures requérant l'emploi de paramètres.
Il est également préférable que l'environnement de développement de VB ou VBE (Visual Basic Editor) vous soit familier, notamment les possibilités de débogage du code.


II. Notions d'objet


II-A. Les objets de la vie courante

Dans la vie courante, nous utilisons quotidiennement des objets.
Nous les définissons par un ensemble de caractéristiques et, généralement, nous pouvons agir avec ces objets.

Ainsi, si je regarde une boite à chaussures, je peux la définir.
Elle est noire, elle fait 40x18x12cm, ...
Je peux l'ouvrir, la fermer, la remplir, la vider,...

Ma voiture possède quatre roues, un volant, un moteur de telle cylindrée.
Je peux la faire avancer, la stopper, ...

Dans ces exemples, nous discernons que nos objets possèdent des caractéristiques qui leurs sont propres, et que nous pouvons définir des actions réalisables sur ou avec ces objets.


II-B. Les objets informatiques

Un objet informatique est similaire à un objet de la vie courante, et nous en utilisons quotidiennement dans nos codes VBA.

Ces objets possèdent des caractéristiques qui leur sont propres et nous pouvons agir sur ou avec ces objets.

Les caractéristiques d'un objet informatique sont appelées les propriétés de l'objet.
Les actions que nous pouvons réaliser sur ou grâce à ces objets sont appelées des méthodes.

Lorsque nous souhaitons utiliser un objet, nous devons donc connaître les propriétés de l'objet mises à notre disposition, et nous devons connaître aussi les méthodes utilisables sur cet objet.


II-B-1. Quelques objets informatiques

En VB6, nous utilisons tout le temps des objets. Tous les contrôles que nous plaçons sur un formulaire (qui est lui-même un objet) sont des objets.

En VBA pour Excel, nous manipulons les objets Range (plage de cellules), Worksheet (feuille de calcul), Workbook (classeur), ...

En VBA pour Word, nous manipulerons les objets Word, Document, ...

En VBA pour Access, nous manipulerons les objets Form, Database, Recordset

En VB6 ou VBA, nous référençons parfois des bibliothèques d'objets externes, pour manipuler des objets particuliers. Par exemple, l'utilisation de la bibliothèque Microsoft Scripting Runtime permet de manipuler des objets Fichier, dossier, ... non utilisables par défaut dans VB6 ou VBA.


II-B-2. L'explorateur d'objets en VB et VBA

L'explorateur d'objets permet... d'explorer les objets, c'est-à-dire d'en afficher les propriétés, méthodes et évènements.

En VB 6.0 comme en VBA, l'affichage de l'explorateur d'objets est possible via le menu Affichage/Explorateur d'objets ou par le raccourci F2.

Lorsque l'explorateur d'objets est affiché, on peut alors choisir d'afficher les objets de toutes les bibliothèques disponibles du projet, ou de restreindre la liste des obets à une bibliothèque particulière.

On peut alors choisir l'objet pour lequel on souhaite afficher les propriétés, méthodes et évènements.

L'objet Form de la bibliothèque VB

L'objet Workbook de la bibliothèque Excel

III. Utilisation de variables simples, puis d'un "pseudo-objet", le type personnalisé

Lorsque l'on doit utiliser un "objet" informatique, on a trois possiblités. La première consiste à créer autant de variables que de propriétés.

La seconde utilise un type personnalisé.

La troisième, enfin, passe par l'utilisation d'une classe personnalisée.

Avant d'aborder la création d'une classe personnalisée, je vais brièvement exposer les deux premières méthodes, ne serait-ce que pour démontrer la puissance d'une classe par rapport aux variables simples et aux types personnalisés.

Pour ceux qui connaissent l'histoire des trois petits cochons, on peut imaginer la première solution comme étant la maison de paille, le type personnalisé étant la maison de bois, la classe personnalisée comme la maison de briques...


III-A. Manipulation des données d'un contact sans utilisation d'un type personnalisé

Si je souhaite manipuler les données d'un contact, je dois déclarer autant de variables que j'ai de données (champs) pour mon contact, puis leur attribuer les données de mon contact, et enfin les utiliser, par exemple au sein d'une procédure qui affiche un message à l'écran.

Sub UtiliserContact()
    Dim ContactNom As String
    Dim ContactPrenom As String
    Dim ContactAdresse As String
    Dim ContactCP As String
    Dim ContactLocalite As String
    Dim ContactDateNaissance As Date
    
    ContactNom = "Fauconnier"
    ContactPrenom = "Pierre"
    ContactAdresse = "20, Jevoumont"
    ContactCP = "4910"
    ContactLocalite = "Theux"
    ContactDateNaissance = DateSerial(1966, 12, 26)
    
    AfficherMessageContact ContactNom, ContactPrenom, ContactAdresse, _
        ContactCP, ContactLocalite, ContactDateNaissance
End Sub

Sub AfficherMessageContact(Nom As String, Prenom As String, Adresse As String, _
    CP As String, Localite As String, DateNaissance As Date)
    MsgBox "Bonjour " & Prenom & " " & Nom & "." & vbCrLf & _
        "Vous habitez " & Adresse & " à " & CP & " " & Localite & "." & vbCrLf & _
        "Vous êtes  le " & Format(DateNaissance, "dddd dd mmmm yyyy"), vbOKOnly, "Salutations"
End Sub
Ce qui me donnera le résultat suivant à l'écran.


III-A-1. Limites de l'utilisation de variables simples

Les limites du code présenté ci-dessus sont évidentes.

Chaque fois que je souhaite utiliser les données d'un autre contact, je dois réinitialiser mes variables, avec le risque d'en oublier, et donc de mélanger les données de mes contacts.

De plus, passer les variables à une procédure ou une fonction qui doit les utiliser n'est déjà pas pratique avec six variables...

...
    AfficherMessageContact ContactNom, ContactPrenom, ContactAdresse, _
        ContactCP, ContactLocalite, ContactDateNaissance
...

Sub AfficherMessageContact(Nom As String, Prenom As String, Adresse As String, _
...
End Sub
Imaginez ce que cela donnerait avec un objet défini par vingt ou trente champs...

Enfin, si je veux utiliser simultanément les données de plusieurs contacts, je vais devoir créer autant de variables ContactNom1, ContactNom2, ... que j'ai de contacts à gérer simultanément. Mission impossible!!


III-B. Qu'est-ce qu'une variable de type personnalisé et quand créer un type personnalisé?

Une variable de type personnalisé est un groupe de plusieurs variables simples dont le type personnalisé concrétise la structure.

Un type personnalisé sera créé lorsqu'il s'avérera nécessaire de manipuler plusieurs variables comme si elles représentaient une entité.
L'utilisation de variables de type personnalisé répondra partiellement aux objections émises plus haut quant à l'utilisation de variables simples.


III-C. Création d'un type personnalisé

Créer un type personnalisé de variable, c'est définir la structure de la variable, préciser quelles sont les variables simples qui seront groupées.

Les variables utilisées plus haut dans le cours constituent la structure de mon type personnalisé.
Je vais les réutiliser en les modifiant légèrement et créer, ou plutôt définir mon type personnalisé avec le code suivant:

Public Type tpContact
    Nom As String
    Prenom As String
    Adresse As String
    CP As String
    Localite As String
    DateNaissance As Date
End Type
info Remarquez qu'ici, j'ai supprimé le préfixe Contact pour mes variables, puisqu'elles sont définies à l'intérieur de mon type personnalisé.
warning Ce code se place toujours en tête de module standard. Il ne peut jamais être utilisé dans le corps d'une procédure ou d'une fonction.

III-D. Utilisation de mon type personnalisé

Je peux maintenant utiliser ce type personnalisé dans mon code

Sub UtiliserContact()
    Dim Contact As tpContact
    
    With Contact
        .Nom = "Fauconnier"
        .Prenom = "Pierre"
        .Adresse = "20, Jevoumont"
        .CP = "4910"
        .Localite = "Theux"
        .DateNaissance = DateSerial(1966, 12, 26)
    End With
    
    AfficherMessageContact Contact
End Sub

Sub AfficherMessageContact(ByRef Contact As tpContact)
    With Contact
        MsgBox "Bonjour " & .Prenom & " " & .Nom & "." & vbCrLf & _
            "Vous habitez " & .Adresse & " à " & .CP & " " & .Localite & "." & vbCrLf & _
            "Vous êtes  le " & Format(.DateNaissance, "dddd dd mmmm yyyy"), vbOKOnly, "Salutations"
    End With
End Sub
Ce qui me donne le même résultat que tout à l'heure.


III-E. Différences entre l'utilisation de variables et l'utilisation d'un type personnalisé

Après avoir créé mon type personnalisé, j'utilise une variable de ce type au travers de mon code, en étant certain d'emporter avec moi la structure complète de ma variable.

De plus, l'écriture et la lecture du code sont plus simples, notamment lorsque je dois passer ma variable en argument d'une fonction ou d'une procédure.

...
    AfficherMessageContact Contact
End Sub

Sub AfficherMessageContact(Contact As tpContact)
...
est plus simple à écrire et à lire que

...
    AfficherMessageContact ContactNom, ContactPrenom, ContactAdresse, _
        ContactCP, ContactLocalite, ContactDateNaissance
End Sub

Sub AfficherMessageContact(Nom As String, Prenom As String, Adresse As String, _
    CP As String, Localite As String, DateNaissance As Date)
...
Enfin, la maintenance de mon code est simplifiée lorsque la structure de ma variable change.

En effet, si je dois ajouter un "champ" à mon type personnalisé, les modifications se limitent à l'affectation du nouveau champ et à la récupération de sa valeur. Les passages et récupérations d'un paramètre contact ne changent pas.


III-F. Limites de l'utilisation d'un type personnalisé

L'utilisation d'un type personnalisé ne permet pas le traitement des données à l'intérieur de sa structure.
La vérification et le traitement des données sont délégués au code appelant, ce qui limite considérablement la portabilité du type.

En effet, dans l'exemple de l'utilisation de ma variable Contact, je dois déléguer au code appelant la vérification de date de naissance. Nulle part dans la structure Type... End Type, je n'ai la possibilité d'effectuer des actions relatives à la saisie d'informations.

De plus, la gestion des erreurs est également déléguée au code appelant.

Enfin, je ne peux gérer aucun évènement relatif à un type personnalisé.


IV. Une classe pour gérer des contacts

L'utilisation d'une classe personnalisée va balayer ces restrictions et me donner la possibilité de mettre à disposition du code utilisateur de ma classe des propriétés, méthodes, erreurs et évènements.

Dans la suite du cours, nous allons avancer petit à petit dans la création d'une classe permettant de gérer des contacts.

La classe que nous allons créer dans un premier temps ne sera vraiment pas professionnelle, mais nous améliorerons le code petit à petit pour intégrer calmement les notions essentielles à la création de classes sûres et portables.


IV-A. Notion de classe,notion d'objet, notion d'encapsulation


IV-A-1. Notion de classe

La classe représente la structure d'un objet. En cela, elle est comparable aux lignes de définition Type... End Type.


IV-A-2. Notion d'objet

Un objet est une variable dont le type s'appuie sur une classe. Que ce soit en VB ou en VBA, cette classe peut être personnalisée ou mise à disposition par l'application.

VB 6.0 comme VBA permettent d'utiliser des références externes. Dans VB 6.0, le menu Projet/Références... permet d'ajouter une référence. Dans VBA, c'est via le menu Outils/Références... que vous avez la possibilité d'ajouter une référence externe.

idea Ainsi, en Excel, Dim MaFeuille As Worksheet créera un objet appelé MaFeuille qui s'appuiera sur la classe qui définit les objets de type WorkSheet, c'est-à-dire les feuilles de calcul.

IV-A-3. Notion d'encapsulation

Nous devrons toujours veiller, lorsque nous construisons une classe, à ce qu'elle soit "encapsulée".
Cela veut dire qu'à aucun moment, notre classe ne doit avoir besoin de données externes pour fonctionner. Dans les faits, cela veut dire que notre classe ne peut jamais faire appel à une variable extérieure à la portée du module de classe.

De même, une classe ne devrait jamais donner la main à l'utilisateur via par exemple un msgbox ou un inputbox. Il faudra donc développer à l'intérieur du module de classe des événements et des gestions d'erreurs qui rendront la main au code appelant.

Ces notions seront vues dans la suite du cours.


IV-B. Création de notre première classe

La classe que nous allons créer va nous permettre de manipuler un objet contact.


IV-B-1. Module de classe


IV-B-1-a. Ajout d'un module de classe en VB 6.0

En VB 6.0, nous créerons une classe personnalisée en ajoutant un module de classe via le menu Projet/Ajouter un module de classe

Nous choisissons alors d'ajouter le module de classe parmi les différents icônes proposés.

Le nouveau module de classe apparaît dans l'arborescence de notre projet, sous le noeud Modules de classe

La première chose que nous allons faire, c'est renommer le module, car c'est lui qui déterminera le nom de notre classe.
Ce nom sera donc choisi avec soin, en évitant notamment les noms réservés par VB 6.0.


IV-B-1-b. Ajout d'un module de classe en VBA

En VBA, nous créerons une classe personnalisée par l'ajout d'un module de classe au sein de notre projet.

info Les illustrations proviennent d'un VBA pour EXCEL, mais vous pouvez les transposer sans problème sur Word, PowerPoint, Access, Outlook, ...
Pour ajouter un module de classe, utilisons le menu Insertion/Module de classe.
Nous pouvons aussi utiliser le bouton d'outil d'ajout de module.

Un nouveau module apparaît dans l'arborescence du projet, dans le noeud Modules de classe.

La première chose que nous allons faire, c'est renommer le module, car c'est lui qui déterminera le nom de notre classe.
Ce nom sera donc choisi avec soin, en évitant notamment les noms déjà utilisés par VBA.


IV-B-2. Création de propriétés simples pour notre classe

warning Ce que nous allons voir maintenant est à proscrire en utilisation professionnelle de classes personnalisées.
La seule raison de leur mention ici est de permettre une prise en main "pas à pas" des notions nécessaires à la réalisation d'une classe performante.
Pour ajouter des propriétés simples à notre classe, il nous suffit de déclarer des variables publiques au sein de notre module de classe.

Pour cela, nous pouvons reprendre la structure de notre type personnalisé.
Le code est le suivant:

Public Nom As String
Public Prenom As String
Public Adresse As String
Public CP As String
Public Localite As String
Public DateNaissance As Date
Public Sexe As String
Ces variables publiques, parce que déclarées au sein d'un module de classe, sont des propriétés en lecture/écriture pour les objets qui s'appuieront sur notre classe.

warning Le terme variable publique est utilisé ici abusivement. La déclaration de variables via Public ... dans un module de classe ne crée pas des variables publiques utilisables partout dans le projet, mais bien des propriétés publiques mises à disposition du code appelant par la classe dont l'objet est issu.

A l'extérieur du module de classe, ces propriétés devront être préfixées du nom de l'objet issu de la classe personnalisée.

IV-B-3. Utilisation de notre classe au sein d'un code

Pour utiliser un objet de type cContact au sein d'un code, nous utiliserons la même technique que pour notre type personnalisé.

En reprenant le code utilisé plus haut, nous avons deux modifications à réaliser pour utiliser notre classe plutôt que notre type personnalisé.
Voici le code:

Sub UtiliserContact()
    Dim Contact As New cContact
    
    With Contact
        .Nom = "Fauconnier"
        .Prenom = "Pierre"
        .Adresse = "20, Jevoumont"
        .CP = "4910"
        .Localite = "Theux"
        .DateNaissance = DateSerial(1966, 12, 26)
        .Sexe = "masculin"
    End With
    
    AfficherMessageContact Contact
End Sub

Sub AfficherMessageContact(Contact As cContact)
    With Contact
        MsgBox "Bonjour " & .Prenom & " " & .Nom & "." & vbCrLf & _
            "Vous habitez " & .Adresse & " à " & .CP & " " & .Localite & "." & vbCrLf & _
            "Vous êtes  le " & Format(.DateNaissance, "dddd dd mmmm yyyy") & ".", vbOKOnly, "Salutations"
    End With
End Sub
La saisie semi-automatique permet, ici aussi, d'utiliser la liste des objets disponibles en fonction de la saisie.

Et voici les modifications à réaliser:

Le résultat est toujours le même, à savoir l'affichage d'un message de bienvenue.

warning Attention! Bien que nous ayons déclaré nos variables publiques, il n'est pas possible de les utiliser telles quelles ailleurs que dans notre module de classe.
Ainsi, le code Debug.Print DateNaissance à l'extérieur de notre code provoquera une erreur de compilation.

IV-B-4. Conclusions

Nous venons de voir comment créer notre première classe.
Il n'y a pas de quoi fouetter un chat. Nous ne savons pas mieux contrôler les données avec ce code qu'avec l'utilisation d'un type personnalisé.

Néanmoins, nous avons vu comment créer un module de classe, lui affecter un nom qui sera celui de la classe que nous créons, et nous avons ajouté des variables "publiques" qui sont des propriétés en lecture/écriture disponibles pour les objets de notre classe.


IV-C. Création de vraies propriétés

Déclarer des variables publiques au sein d'un module de classe est certes rapide, mais peu intéressant.
Pour pouvoir manipuler, contrôler et travailler avec les propriétés d'un objet, nous allons déclarer des ... propriétés.


IV-C-1. Notions de propriétés en lecture/écriture, en lecture seule et en écriture seule


IV-C-2. Propriétés en lecture/écriture

Une propriété en lecture/écriture est une propriété qui peut être lue ET modifiée.
Exemple: La propriété DateNaissance doit être en lecture pour pouvoir la récupérer et en écriture pour pouvoir la définir pour un contact particulier.


IV-C-3. Propriétés en lecture seule

Une propriété en lecture seule ne peut être ni définie, ni modifiée.
Exemple: si je dote ma classe d'une propriété Age, elle sera en lecture seule car elle dépendra de la propriété DateNaissance, qui sera, elle, en lecture/écriture.


IV-C-4. Propriétés en écriture seule

Une propriété pourrait être en écriture seule, et donc définissable mais non lisible.
Je ne vois pas d'exemple concret pour ce cas.


IV-C-5. Propriétés en lecture/écriture qui basculent en lecture seule

Certaines propriétés doivent être définies une fois, puis être verrouillées pour ne plus pouvoir être modifiées.
Elles sont dès lors en lecture/écriture mais le code les fera basculer en lecture seule pour éviter leur modification.
Exemple: Une propriété ID qui doit être définie mais qui ne peut par la suite être modifiée. C'est le cas des clés primaires, pour ceux qui connaissent.
Nous verrons ce cas particulier dans la suite du cours.


IV-C-6. Utilisation de Property Get et Property Let

Property Get et Property Let permettent la création de propriétés au sein de la classe.

Property Get permet la lecture d'une propriété, Property Let permet l'écriture d'une propriété.


IV-C-6-a. La propriété "Nom" en lecture-écriture

La création d'une propriété passe pas deux étapes; la définition d'une variable privée, et la création des blocs Property Get et Property Let.

Modifions le code de notre classe en modifiant la ligne

Public Nom As String
pour définir une variable privée

Private mNom As String
Remarquez que ma variable a changé de nom, par l'ajout d'un préfixe "m" précisant la limite de sa portée au module.
Cette variable ne sera donc pas manipulable par le code appelant qui utilisera notre objet.

La définition du nom de notre contact s'effectuera via le code

Property Get Nom() As String
    ' Propriété en lecture
    Nom = mNom
End Property

Property Let Nom(Nom As String)
    ' Propriété en écriture
    mNom = Nom
End Property
info Notons que ces modifications n'ajoutent actuellement rien à notre classe par rapport à l'utilisation d'une variable déclarée avec Public. Patience...
Notez aussi que les propriétés ne sont pas déclarées Public, car elles le sont d'office. C'est leur raison d'être!

Notons cependant que des propriétés peuvent être déclarées Private pour n'être utilisables qu'à l'intérieur du module de classe.

IV-C-6-a-i. Fonctionnement du code
Pour nous aider à comprendre comment le code fonctionne avec les propriétés d'une classe, nous allons démarrer le code appelant vu plus haut avec la méthode "pas à pas", en mettant un point d'arrêt sur la ligne With Contact de la procédure UtiliserConctact

Puis nous démarrons le code. L'exécution s'arrête sur With contact. Nous sommes dans le module standard qui contient la procédure UtiliserContact.

Nous pressons sur F8 pour passer à la ligne suivante, puis encore sur F8. Le contrôle du code passe dans le module de classe pour s'arrêter sur Property Let.

L'infobulle nous montre que le paramètre Nom possède la valeur "Fauconnier" passée par le module standard.
Nous connaissons déjà le fonctionnement des paramètres, puisqu'il est identique dans une propriété à celui d'une procédure ou d'une fonction dans VBA. Rien de nouveau sous le soleil de ce côté-là.

Pressons F8. Le code repasse dans le module standard, et pressons F8 jusqu'à nous arrêter sur la ligne End Property. L'infobulle nous montre que la valeur du paramètre a été passée à la variable privée mNom.

Pressons F8 plusieurs fois pour arriver sur la ligne MsgBox... de la procédure AfficherMessageContact

Puis pressons F8, pour constater que le code repasse dans le module de classe, et s'arrête sur la ligne Property Get Nom(). Le code va récupérer la valeur de la variable mNom

Pour la passer au paramètre Nom

Ce qui permettra l'affichage du nom au sein du MsgBox.

On comprend donc maintenant le fonctionnement et le parcours du code au sein des propriétés de la classe. Mais à quoi cela sert-il?


IV-C-6-a-ii. Contrôle de la saisie du nom en vue de sa modification
L'intérêt de passer par Property Let pour définir le nom de notre contact, c'est que nous pouvons ajouter du code au sein de la propriété, ce qui était impossible avec une variable de type personnalisé ou une variable publique de notre module de classe.

Imaginons que nous voulons que les noms de nos contacts soient systématiquement en majuscules. Grâce à Property Let, nous n'aurons aucune difficulté à satisfaire à cette exigence.
Modifions le code comme suit:

Property Let Nom(Nom As String)
    ' Propriété en écriture
    mNom = UCase(Nom)
End Property
En plaçant un point d'arrêt sur End Property de cette propriété,

Nous verrons, grâce à l'infobulle, que mNom contient le nom en majuscules.

A la lecture de la propriété, le paramètre Nom recevra la valeur de mNom pour afficher, cette fois, un message différent de ceux vus précédemment.


IV-C-6-a-iii. Adaptation du code: Transformation des variables en propriétés
Maintenant que nous avons compris l'intérêt d'utiliser des propriétés plutôt que des variables, nous pouvons modifier le code en transformant toutes les variables en propriétés.
Toutes ces propriétés sont en lecture/écriture.

Option Explicit

Private mNom As String
Private mPrenom As String
Private mAdresse As String
Private mCP As String
Private mLocalite As String
Private mDateNaissance As Date
Private mSexe As String

Property Get Nom() As String
    ' Propriété en lecture
    Nom = mNom
End Property

Property Let Nom(Nom As String)
    ' Propriété en écriture
    mNom = UCase(Nom)
End Property

Property Get Prenom() As String
    ' Propriété en lecture
    Prenom = mPrenom
End Property

Property Let Prenom(Prenom As String)
    ' Propriété en écriture
    mPrenom = UCase(Prenom)
End Property

Property Get Adresse() As String
    ' Propriété en lecture
    Adresse = mAdresse
End Property

Property Let Adresse(Adresse As String)
    ' Propriété en écriture
    mAdresse = UCase(Adresse)
End Property

Property Get CP() As String
    ' Propriété en lecture
    CP = mCP
End Property

Property Let CP(CP As String)
    ' Propriété en écriture
    mCP = UCase(CP)
End Property

Property Get Localite() As String
    ' Propriété en lecture
    Localite = mLocalite
End Property

Property Let Localite(Localite As String)
    ' Propriété en écriture
    mLocalite = UCase(Localite)
End Property

Property Get DateNaissance() As Date
    ' Propriété en lecture
    DateNaissance = mDateNaissance
End Property

Property Let DateNaissance(DateNaissance As Date)
    ' Propriété en écriture
    mDateNaissance = DateNaissance
End Property

Property Get Sexe() As String
    ' Propriété en lecture
    Sexe = mSexe
End Property

Property Let Sexe(Sexe As String)
    ' Propriété en écriture
    mSexe = UCase(Sexe)
End Property
warning Remarquez qu'il faut une similitude de type entre une propriété en lecture et la même propriété en écriture.
Ainsi, si la propriété en lecture est typée String, la propriété en écriture doit recevoir un paramètre typé String.

IV-C-6-a-iv. La propriété "Age" en lecture seule
Après avoir vu comment ajouter du code dans un Property Let, nous allons aborder une propriété en lecture seule avec du code pour calculer la valeur de la propriété.

Pour éviter que le programmeur du code appelant doive créer une fonction qui calcule l'âge du contact par rapport à la date de naissance, nous allons créer une propriété Age au sein de notre classe. Le code appelant devra alors seulement lire la propriété Age de l'objet contact, sans se soucier de l'algorithme utilisé.

Voici le code permettant de calculer l'âge révolu du contact.

Property Get Age() As Integer
    Age = Int((Date - mDateNaissance) / 365)
End Property
idea Il existe une multitude de façons de calculer l'âge, avec ou sans la fonction DateDiff. Ce cours ayant pour objectif l'apprentissage des classes personnalisées et non les algorithmes de calcul d'âge, le lecteur acceptera ma façon de calculer et la considérera pour ce qu'elle est, à savoir l'illustration d'une création de propriété en lecture seule.
Ainsi, le code suivant, placé dans un module standard, permettra de connaître l'âge d'un contact en fonction de sa date de naissance.

Sub CreerContactAge()
    Dim Contact As New cContact
    
    Contact.Prenom = "Pierre"
    Contact.DateNaissance = DateSerial(1966, 12, 26)
    
    MsgBox Contact.Prenom & " a " & Contact.Age & " ans"
End Sub
Ce qui affichera le message suivant

info Dans ce cas précis, mDateNaissance étant une date, le fait de ne pas spécifier la date de naissance pose simplement un problème de calcul, et le résultat est erroné.
Il n'y a pas d'erreur amenant à un débogage ou un plantage, mais il faudra être vigilant et envisager tous les cas possibles.
Nous verrons très bientôt comment gérer ce type de situation.

IV-C-6-a-v. Un petit mot sur l'explorateur d'objets
J'ai abordé plus haut dans le cours l'explorateur d'objets. Cet explorateur permet également de parcourir les objets que nous créons.

Si je demande à l'explorateur d'objets de m'afficher les propriétés de ma classe cContacts, j'obtiendrai l'affichage suivant:

En sélectionnant une valeur dans la liste, j'obtiens les spécifications de cette propriété ou méthode



IV-C-6-a-vi. Conclusions
Nous venons d'approcher la puissance des propriétés de notre classe, car seule notre imagination va nous bloquer.

Si, par exemple, vous devez souvent calculer des emprunts, les taux de remboursement, ..., vous pouvez vous définir une classe cEmprunts et créer des méthodes et des propriétés pour cette classe.

Vous mettez alors à disposition du code, voire d'autres programmeurs, une classe qui peut être utilisée, même par quelqu'un qui ne connaît aucune formule de calcul...

Dans la suite du cours, nous allons enrichir notre classe avec des créations d'erreurs et des déclenchements d'évènements.
Nous donnerons également au code appelant les moyens de contrôler l'exécution du code à l'intérieur de la classe. Mais, ... Patience!


IV-D. Déclenchement d'erreurs au sein de notre classe

Lorsque nous avons créé la propriété Age, nous avons remarqué que l'âge pouvait être erroné si la date de naissance n'était pas spécifiée.

Nous pourrions aussi avoir des surprises désagréables si nous créons un contact pour une personne qui n'est pas encore née, en introduisant une date ultérieure à la date système. Gênant...

Nous allons donc contrôler, dans Property Let DateNaissance, que la date passée en paramètre est valide.
Cela se fera très facilement avec le code suivant


Property Let DateNaissance(DateNaissance As Date)
    ' Propriété en écriture
    If DateNaissance <= Date Then
        mDateNaissance = DateNaissance
        Else
        ...
    End If
    
End Property
Jusque là, ce n'est pas trop compliqué. Mais par quoi faut-il remplacer les ... ? Par ceci ?


Property Let DateNaissance(DateNaissance As Date)
    ' Propriété en écriture
    If DateNaissance <= Date Then
        mDateNaissance = DateNaissance
        Else
        MsgBox "Date non valide", vbOKOnly + vbExclamation, "Erreur de saisie"
    End If
    
End Property
En effet, si je passe comme date de naissance une date ultérieure à la date du jour, j'ai un beau message d'erreur.

Mais, ce faisant, j'enfreins la règle d'encapsulation vue plus haut, car ma classe passe outre le code appelant pour s'adresser directement à l'utilisateur derrière son écran, sans donner la possibilité au code appelant de reprendre la main.

warning Une classe doit TOUJOURS, en cas d'erreur, rendre la main au code appelant et JAMAIS à l'utilisateur.
C'est au code appelant qu'il revient de gérer l'erreur survenue dans la classe.
Nous allons donc devoir créer du code au sein de la classe pour rendre la main au code appelant et lui déléguer la responsabilité de traiter l'erreur.

warning La classe a la responsabilité de signaler l'erreur, le code appelant a la responsabilité de le gérer.

IV-D-1. Génération d'une erreur au sein de la classe

Pour informer le code appelant d'une erreur, dans le cas présent une erreur de saisie, nous allons générer une erreur avec Err.Raise Number, [Source], [Description],...


Property Let DateNaissance(DateNaissance As Date)
    ' Propriété en écriture
    If DateNaissance <= Date Then
        mDateNaissance = DateNaissance
        Else
        Err.Raise Number:=vbObjectError + 1, Description:="Date non valide"
    End If
    
End Property
Pour générer l'erreur, nous avons besoin d'un numéro d'erreur, et optionnellement d'une source et d'une description de l'erreur. Nous pouvons également définir des paramètres utiles lors de l'utilisation de fichier d'aide, mais je n'en parlerai pas ici.

Certaines plages de numéros d'erreur étant réservées par Windows et VBA, Nous utiliserons la constante vbobjecterror en lui ajoutant des unités, et il faudra, pour le support technique, tenir des fiches à jour avec le numéro de l'erreur et les lignes de code concernées, pour faciliter la maintenance de code.

En plus de ce numéro d'erreur, nous utiliserons le paramètre Description qui explicitera l'erreur rencontrée.

Si, après cette modification de la propriété, nous relançons le code, nous avons un message d'erreur, mais au niveau du code appelant et plus au niveau de l'utilisateur "final".

On comprend donc clairement ici que la main est rendue au code appelant. A lui la responsabilité de la gestion de l'erreur, par exemple avec le code suivant


    On Error GoTo Erreurs
    Contact.Prenom = "Pierre"
    Contact.DateNaissance = DateSerial(2008, 12, 26)
    
    MsgBox Contact.Prenom & " a " & Contact.Age & " ans"
    
Erreurs:
    Select Case Err
        Case -2147221503
            MsgBox "La date saisie n'est pas valide et ne sera pas enregistrée", vbOKOnly + vbExclamation, "Erreur de saisie"
            Resume Next
    End Select
C'est donc bien le code appelant qui reprend la main et qui décide de la façon de traiter l'erreur.


IV-E. Mettre des évènements à disposition du code appelant

VB 6.0 et VBA permettent de créer des évènements liés à une classe personnalisée. Ces évènements sont levés lors de certaines manipulations à l'intérieur de la classe et passent la main au code appelant qui peut choisir de les gérer ou pas


IV-E-1. Exemples d'évènements mis à disposition par des classes d'objets

Nous connaissons tous la gestion des évènements pour des objets couramment utilisés lors d'une programmation en VB 6.0 ou en VBA.

Voici par exemple la gestion de l'évènement de chargement d'un "form" en VB 6.0

... et voici l'illustration de la gestion de l'évènement "SelectionChange" d'une feuille de calcul Excel, recevant en paramètre la cellule active de la plage sélectionnée.

info Les évènements qu'il est possible de gérer dépendent évidemment de l'objet que l'on manipule. Ainsi, dans une classe personnalisée, il n'y a par défaut aucun évènement à la disposition du code qui exploite un objet issu de cette classe. C'est au concepteur de la classe qu'il revient de créer les évènements qu'il souhaite mettre à disposition du code utilisateur.

IV-E-2. Création d'un évènement pour notre classe personnalisée

warning La mise à disposition d'évènements pour des objets d'une classe personnalisée n'impose pas la gestion de ces évènements par le code appelant. Dans Excel, lorsque vous manipulez des feuilles de calcul, vous n'êtes pas tenus de gérer les évènements mis à votre disposition. Il en est de même pour les évènements de vos classes personnalisées, qui ne seront peut-être jamais gérés par le code appelant. C'est ce qui différencie les évènements des erreurs, qui sont, quant à elles, levées systématiquement, qu'elles soient gérées ou non par le code appelant.

IV-E-2-a. Création et gestion d'un évènement sans paramètre

Imaginons que nous souhaitons que le code appelant puisse gérer le fait que l'anniversaire du contact surviendra dans les 10 jours, et que nous souhaitons déclencher l'évènement lors de la saisie de sa date de naissance.


IV-E-2-a-i. Création de l'évènement
Tout d'abord, il faut déclarer l'évènement. Celui-ci se déclare avant la première méthode, la première propriété ou la première fonction, tout en haut du module. Créons un évènement appelé AnniversaireDans10Jours. Le code utilisé est simple

Public Event AnniversaireDans10jours()
Lorsque cela est fait, il nous reste à déclencher l'évènement lorsque la condition est remplie. Pour cela, nous allons modifier le code de property let DateNaissance, de façon à tester la date d'anniversaire


Property Let DateNaissance(DateNaissance As Date)
    ' Propriété en écriture
    Dim DateAnniversaire As Date
    mDateNaissance = DateNaissance
    
    ' Calcul de la date anniversaire pour l'année en cours
    DateAnniversaire = DateSerial(Year(Date), Month(DateNaissance), Day(DateNaissance))
    If DateAnniversaire >= Date And DateAnniversaire <= Date + 10 Then RaiseEvent AnniversaireDans10jours
End Property
Avec la saisie semi-automatique, la liste des évènements disponibles pour l'objet apparaît après la saisie de RaiseEvent

Nous venons donc de créer un évènement pour les objets de notre classe. Si cet évènement est géré par le code appelant, ce dernier pourra, par exemple, avertir l'utilisateur que le contact qu'il est en train de gérer a son anniversaire dans les dix prochains jours.


IV-E-2-a-ii. Gestion de l'évènement dans le code appelant
Pour pouvoir gérer l'évènement de l'objet issu de notre classe cContact, nous devons déclarer à VB 6.0 ou VBA que nous voulons gérer les évènements pour cet objet. Pour cela, il suffit de déclarer notre objet de la façon suivante, en utilisant Dim ou Public en fonction de la portée d'utilisation voulue pour notre objet.

	Dim WithEvents oContact As cContact
warning Tant en VB 6.0 qu'en VBA, les modules standard ne permettent pas de gérer des évènements pour des objets, qu'ils soient personnalisés ou non. Il n'est donc pas possible de déclarer des objets avec la clause WithEvents au sein d'un module standard. La ligne est directement refusée et mise en rouge.
info Pour info, la déclaration avec WithEvents d'un objet qui ne possède pas d'évènements ne déclenche pas d'erreur lors de la saisie du code, mais déclenche une erreur à l'exécution. Il n'est donc possible d'utiliser WithEvents que pour des objets pour lesquels il existe des évènements gérables.
Pour illustrer cela, nous allons utiliser un formulaire avec un bouton

Dans un formulaire de notre projet (formulaire pour VB 6.0 ou userform pour VBA), déclarons un objet de type cContact en tête de module.

Option Explicit

Dim WithEvents oContact As cContact
En déclarant notre objet de cette manière, nous pouvons gérer le(s) évènement(s) qui lui sont attachés. En effet, dans la fenêtre du code, nous disposons de l'objet dans la liste déroulante de gauche,

VB 6.0: Objet dans la liste des objets disposant d'évènements

VBA: Objet dans la liste des objets disposant d'évènements
et de la liste de ses évènements dans la liste déroulante de droite.

VB 6.0: Liste des évènements pour l'objet sélectionné dans la liste déroulante de gauche

VBA: Liste des évènements pour l'objet sélectionné dans la liste déroulante de gauche
Lorsque l'objet a été déclaré ce cette manière, je peux gérer l'évènement souhaité


Private Sub oContact_AnniversaireDans10jours()
    MsgBox "L'anniversaire de " & oContact.Prenom & " a lieu dans les 10 prochains jours"
End Sub
Si, sur le formulaire (VB 6.0) ou le userform (VBA), nous plaçons un bouton nommé btnContact, nous pouvons gérer notre contact via un clic sur ce bouton, avec le code suivant

Private Sub btnContact_Click()
    Set oContact = New cContact
    With oContact
        .Prenom = "Manon"
        .DateNaissance = DateSerial(1992, 12, 3)
    End With
End Sub
En démarrant le code, nous aurons le message suivant

warning Pour que l'exemple fonctionne, il faut évidemment que la date de naissance utilisée soit calculée pour que l'anniversaire tombe dans les 10 prochains jours par rapport à la date système de vote pc.
Si nous suivons l'exécution du code pas à pas, nous pouvons comprendre comment la levée de l'évènement fonctionne. Pour cela, plaçons un point d'arrêt sur la ligne de code qui attribue la date de naissance.

Démarrons le code. L'exécution s'arrête sur la ligne qui attribue la date de naissance.

Avec F8, avançons pas à pas. L'exécution saute dans le module de classe, et nous pressons F8 jusqu'à la ligne qui teste la date de naissance

La date de naissance est testée. Si la condition est remplie, l'évènement est généré

L'exécution saute dans le code appelant pour générer l'évènement, et nous constatons que l'affichage du message va avoir lieu

Après affichage du message et clic sur le bouton Ok, on passe à la fin de la gestion de l'évènement dans le code appelant

Puis on retourne dans le code de la classe pour terminer le code lié à la propriété DateNaissance en écriture

Et on repasse dans le code appelant pour continuer l'exécution du code

Comme vous le voyez ici, la mise en place d'un évènement au sein d'une classe est finalement assez simple et s'effectue en deux temps: Déclarer un évènement au niveau du module, puis générer l'évènement dans le code, à l'endroit opportun. Il ne reste plus qu'à choisir de gérer ou non l'évènement dans le code appelant.


IV-E-2-b. Création d'un évènement qui passe un paramètre au code appelant


IV-E-2-b-i. Exemples d'évènements avec paramètre(s)
Certains évènements passent au code appelant un ou plusieurs paramètres. C'est le cas de l'évènement Unload d'un form en VB 6.0, qui passe un paramètre

ou encore de l'évènement BeforeDoubleClick d'une feuille de calcul Excel, qui passe quant à lui deux évènements au code appelant.

Ces paramètres peuvent alors être gérés ou utilisés par le code appelant.


IV-E-2-b-ii. Création de l'évènement au sein de la classe
Il est possible de passer un paramètre au code appelant. Ainsi, on pourrait vouloir passer la date de naissance au code appelant lorsque le contact a son anniversaire dans les 10 jours.

Pour cela, on doit modifier la déclaration de l'évènement.

Il faut aussi modifier également le code qui génère l'évènement, car il doit correspondre à la syntaxe de la déclaration de l'évènement.

Bien entendu, le code qui gère l'évènement doit lui aussi correspondre à la syntaxe de l'évènement paramétré.

Le code appelant est bien entendu libre d'utiliser ou pas le paramètre passé lors de la levée de l'évènement. Ici, le paramètre est utilisé dans un messagebox


IV-E-2-b-iii. Utilisation de l'évènement et de son paramètre dans le code appelant

IV-E-2-c. Modification du déroulement du code dans la classe grâce à un paramètre "décisionnel"


IV-E-2-c-i. Création d'un paramètre décisionnel
Un paramètre décisionnel est un paramètre dont la modification par le code appelant va modifier l'exécution du code au sein de la classe. L'exemple typique de paramètre "décisionnel" est le paramètre Cancel utilisé par nombre de codes évènementiels.

Imaginons que nous voulions contrôler la modification de la propriété sexe de notre contact. On se rend compte rapidement que, sauf à devoir changer le contenu de la garderobe du contact, il peut être utile de mettre à disposition du code appelant un évènement lorsque celui-ci modifie la propriété Sexe du contact.

Nous allons déclarer l'évènement dans la classe en utilisant le code suivant

Public Event ModificationGenre(ByRef Cancel As Boolean)
Remarquez que le paramètre Cancel est passé ByRef.

Il nous faut modifier la propriété Sexe en écriture, dans la classe cContact


Property Let Sexe(Sexe As String)
    ' Propriété en écriture
    Dim Cancel As Boolean
    If mSexe <> "" Then RaiseEvent ModificationGenre(Cancel) ' Teste si le genre a déjà été attribué
    If Not Cancel Then mSexe = UCase(Sexe) ' Si Cancel = FALSE, on n'annule pas la modification...et donc on modifie!
End Property
Le code modifié testera si le genre a déjà été défini. Si oui, l'évènement est généré, à charge pour le code appelant de définir la suite des opérations.


IV-E-2-c-ii. Gestion de l'évènement dans le code appelant
Dans le code appelant (code du form ou du userform), on va gérer l'évènement, puisque nous avons maintenant un deuxième évènement dans la liste de droite.



Private Sub oContact_ModificationGenre(Cancel As Boolean)
    Dim Reponse As VbMsgBoxResult
    
    Reponse = MsgBox("Etes-vous certain de vouloir modifier le genre du contact?", vbYesNo + vbQuestion, "Gestion du contact")
    If Reponse <> vbYes Then Cancel = True
End Sub
info Remarquez que la ligne de déclaration de la procédure évènementielle reprend la structure de la déclaration de l'évènement dans le module de classe, et donc passe le(s) paramètre(s) définis dans cette déclaration.
A nouveau, utilisons l'exécution pas à pas pour bien comprendre ce qui se passe. Pour cela, nous allons utiliser le code appelant suivant, dans la procédure évènementielle Click du bouton btnContact


Private Sub btnContact_Click()
    Set oContact = New cContact
    With oContact
        .Prenom = "Manon"
        .Sexe = "F"
    End With
    
    oContact.Sexe = "M"
    MsgBox oContact.Prenom & ": sexe " & UCase(oContact.Sexe)
End Sub
Plaçons un point d'arrêt sur la ligne qui affecte le genre du contact

Démarrons l'exécution du code, qui s'arrête sur la ligne qui définit pour la première fois le genre du contact

Le code passe dans le module de classe, teste si mSexe est une chaine vide.

Comme c'est le cas, l'évènement n'est pas généré, et le code passe à la ligne suivante, sur laquelle on va tester la variable locale Cancel, définie à False par défaut

Cancel est différent de True, donc la variable mSexe reçoit la valeur passée par le code appelant.

Et le code continue, et repasse dans le code appelant pour, cette fois, modifier le genre du contact, puisque nous venons de l'attribuer à la ligne précédente.

Le code appelant veut modifier la propriété Sexe du contact, le code repasse donc dans le module de classe sur la propriété Sexe en écriture et teste si mSexe est une chaine vide. Ce n'est plus le cas, puisque la valeur "F" a déjà été attribuée

Donc, l'évènement est généré avec Cancel = False (valeur par défaut).

Le code repasse au code appelant puisqu'une procédure évènementielle a été rédigée. Cette procédure évènementielle reçoit bien le paramètre Cancel avec la valeur False

Si nous répondons NON à la question posée, la valeur de Cancel est modifiée

La procédure évènementielle se termine, et le code repasse dans le module de classe pour continuer son exécution. On voit ici que la valeur de Cancel a été modifiée, grâce au mot-cle ByRef utilisé lors de la déclaration de l'évènement en début du module de classe.

Comme Cancel vaut True, mSexe n'est pas modifié. La modification de Cancel par le code appelant a donc bien modifié l'exécution du code à l'intérieur de la classe.

Si nous avions répondu Oui à la question posée par le code appelant, la valeur de Cancel n'aurait pas été modifiée, et donc mSexe aurait reçu la nouvelle valeur, ce qui aurait pour conséquence que notre contact féminin serait devenu un homme...

info On comprend donc mieux ici, gràce à cet exemple, comment fonctionne le paramètre Cancel présent dans de nombreuses procédures évènementielles que nous rencontrons avec les objets que nous utilisons dans nos applications.

V. Conclusions

Cette partie du tutoriel nous a permis de comprendre ce qu'était un objet personnalisé. Nous avons abordé les notions de propriété, génération d'erreurs et génération d'évènements

Nous voici arrivés au terme de la première partie de ce que je souhaite vous expliquer sur le fonctionnement des classes personnalisées.

Dans une seconde partie, nous envisagerons l'utilisation de cette classe "métier" au travers d'une classe qui liera notre contact à une source de données. Nous verrons que peu de choses seront à modifier dans cette nouvelle classe pour lier nos données à un classeur Excel ou à une base de données Access.


VI. Remerciements



Valid XHTML 1.1!Valid CSS!

Copyright © 2008 . Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.