Comment créer nos propres objets VBA avec les classes personnalisées [#30 FORMATION EXCEL VBA COMPLETE]
Pour ce nouveau chapitre de notre formation dédiée à l’apprentissage du développement en VBA pour les débutants, je vais vous montrer comment créer nos propres objets à manipuler en VBA avec les classes personnalisées !
Téléchargement
Vous pouvez télécharger le fichier d'exemple de cet article en cliquant sur le lien suivant :
Tutoriel Vidéo
Partie 1 :
Partie 2 :
1. Retour sur les notions de variables et de classes personnalisées
Au cours des précédents chapitres de cette formation, nous avons déjà eu l’occasion de voir plusieurs méthodes permettant de manipuler des informations dans le langage VBA.
Et la première notion que nous avons ainsi vue consiste à utiliser les variables.
En sachant qu’une variable permet d’enregistrer une information dans un espace alloué de la mémoire de l’ordinateur pour pouvoir la réutiliser ultérieurement.
Le type d’information que la variable va être en mesure d’enregistrer et de restituer va directement dépendre du typage que nous allons mettre en place au moment de la déclaration de la variable. (Certaines variables vont ainsi permettre de manipuler un nombre, d’autres variables un texte, une date, …).
Pour illustrer la notion de variable, nous allons par exemple souhaiter enregistrer les informations d’une personne, comme son prénom et son âge.
Sub lesVariables()
Dim prenom As String
prenom = "Vincent"
Dim age As Integer
age = 20
End Sub
Pour utiliser une variable, nous commençons par la déclarer en utilisant le mot-clé Dim, suivi de son nom et de son type.
Dans cet exemple, nous stockons les informations concernant Vincent, c’est-à-dire son prénom et son âge.
Maintenant, supposons que nous voulions stocker les informations d’une seconde personne.
Trois possibilités s’offrent alors à nous.
Tout d’abord nous pourrions créer une multiplicité de variable pour enregistrer toutes les informations de chacune des personnes concernées :
Sub lesVariables()
Dim prenomClient1 As String
prenomClient1 = "Vincent"
Dim ageClient1 As Integer
ageClient1 = 20
Dim prenomClient2 As String
prenomClient2 = "Antoine"
Dim ageClient2 As String
ageClient2 = 26 Debug.Print prenomClient1
End Sub
À ce moment-là, il sera nécessaire de manipuler toutes ces variables avec la plus grande des précautions afin de ne pas se mélanger les pinceaux entre chacune d’elles !
D’autant plus qu’ici l’exemple est exagérément très simple, mais imaginez que nous ayons besoin d’enregistrer plus d’informations (comme nom de famille, adresse, numéro de téléphone, date de naissance, …) et qu’en plus de cela le nombre de personne ne se limite pas qu’à deux individus, mais à plusieurs dizaines, voire centaines !
Dans ce cas cette solution ne sera évidemment pas envisageable, tant le temps nécessaire serait trop important.
En revanche, une seconde possibilité pourrait être d’enregistrer les informations dans des tableaux.
Un tableau en programmation est une sorte de variable capable d’enregistrer plusieurs informations, chacune d’entre elles étant identifiable par un numéro d’index.
Pour déclarer un tableau, nous utilisons la même méthode que nous venons de revoir pour les variables, nous utilisons en plus des parenthèses pour définir le nombre d’éléments pouvant être enregistrés à l’intérieur de celui-ci.
Sub lesVariablesDansDesTableaux()
Dim prenomClient(1 To 2) As String
prenomClient(1) = "Vincent"
prenomClient(2) = "Antoine"
Dim ageClient(1 To 2) As Integer
ageClient(1) = 20
ageClient(2) = 26 Debug.Print prenomClient(1)
End Sub
Lors de la déclaration de la variable prenomClient, nous avons précisé que celle-ci pouvait prendre pour index les valeurs 1 ou 2.
Nous pourrions également déclarer la variable de la manière suivante :
Dim prenomClient(1) As String
Mais dans ce cas, les index possibles seraient 0 et 1.
Ici, nous avons défini que lorsque nous appelons l’index n 1 de l’une de ces variables, nous allons récupérer les informations de Vincent, tandis que l’index 2 énumère celles d’Antoine.
Les choses sont alors déjà plus claires, mais cela n’est pas encore suffisant !
Pour aller plus loin encore dans l’utilisation des tableaux, nous pourrions encore utiliser une variable générique qui serait alors un tableau en deux dimensions :
- La première dimension sert à identifier la personne : 1 pour Vincent, 2 pour Antoine,
- La seconde dimension sert à identifier le paramètre : 1 pour le prénom, 2 pour l’âge
Sub lesVariablesDansDesTableaux()
Dim client(1 To 2, 1 To 2) As String
client (1, 1) = "Vincent"
client (1, 2) = 20
client (2, 1) = "Antoine"
client (2, 2) = 26 Debug.Print client (1, 1)
End Sub
Mais les choses sont encore plus complexes à interpréter…
L’étape suivante va alors consister à utiliser un type de variable personnalisé que nous avons pour coutume dans cette formation d’appeler une « super-variable » !
Type tClient
prenom As String
age As Integer
End Type
…
Sub lesSupersVariables()
Dim clientA As tClient
clientA.prenom = "Vincent"
clientA.age = 20
Dim clientB As tClient
clientB.prenom = "Antoine"
clientB.age = 26
Debug.Print clientA.prenom
End Sub
Nous commençons donc par créer le nouveau type de variable personnalisé tout en haut de la feuille de code (en dessous de l’éventuel Option Explicit) en utilisant le mot clé « Type », suivi du nom que nous souhaitons lui donner.
Ici nous l’appelons tClient, le petit « t » permettant d’identifier la présence d’un type personnalisé.
Puis, nous définissons la structure de la variable en venant déclarer des variables qui seront utilisables en tant que pseudo-propriétés de la variable (attention, la déclaration des variables de structure d’un type personnalisé se fait sans utiliser le mot-clé Dim).
Comme nous le voyons sur la suite du code, nous pouvons ensuite déclarer de nouvelles variables en utilisant ce nouveau type, puis ces pseudo-propriétés sont ensuite appelées en utilisant un point de séparation !
Nous pouvons encore faciliter l’interprétation du code en mélangeant les deux techniques que nous venons de découvrir à l’instant, c’est-à-dire d’utiliser le type personnalisé, directement dans un tableau :
Dim client(1 To 2) As tClient
client(1).prenom = "Vincent"
client(1).age = 20
client(2).prenom = "Antoine"
client(2).age = 26
En plus de simplifier la rédaction du code, cette méthode permet de pouvoir passer en revue les différents éléments de chaque variable en utilisant une boucle For :
Comme vous pouvez alors le constater, les différentes solutions que nous venons de revoir ici permettent de simplifier à la fois la création du code en lui-même, mais également sa relecture, ainsi que son interprétation future.
Par contre, cette solution n’est pas encore idéale car ici, nous ne pouvons agir que sur des pseudo-propriétés qui permettent de stocker des valeurs au sein de variables afin de pouvoir les utiliser ultérieurement.
Nous ne pouvons pas utiliser des variables pour effectuer directement des traitements en appelant une méthode, car comme nous l’avons également déjà découvert dans les chapitres précédent, dédiés à la découverte des objets de VBA, l’utilisation des méthodes leur est en effet strictement réservée !
2. Création de notre première classe personnalisée
Mais heureusement, comme nous l’avons vu au tout début de cette formation, le langage VBA est un langage dit « orienté objet », ce qui signifie qu’en plus des objets déjà présents dans VBA, nous allons pouvoir créer nos propres objets !
Et pour cela il va être nécessaire de définir ce que l’on appelle une « classe personnalisée » (à ne pas confondre avec le « type personnalisé »), laquelle servira ensuite de type de déclaration pour l’objet (un peu comme le type personnalisé que nous avons utilisé un peu plus tôt, mais en bien plus puissant !).
La particularité des classes personnalisées, vient du fait que celles-ci vont devoir être définies dans un module spécifique qui porte le nom de « module de classe », et que nous allons pouvoir créer en utilisant le menu Insertion :
Le fait d’isoler ainsi une classe dans un module spécifique permet de la rendre totalement indépendante,
En revanche, le revers de la médaille est qu’il ne lui sera pas permis d’utiliser des données externes !
Un autre atout de travailler avec des Modules de classe, c’est qu’il nous suffira ensuite d’exporter celui-ci pour pouvoir facilement l’utiliser dans d’autres projets, ou même encore le transmettre à d’autres codeurs, qui n’ont même pas besoin de savoir comment celui-ci a été codé pour pouvoir l’utiliser !
Une fois le module de classe ajouté, nous pouvons le retrouver dans l’arborescence du projet de VBE :
Nous allons commencer par renommer le module de classe, car le nom que nous lui donnerons servira à identifier la classe lors de la création de l’objet
Pour cela, après l’avoir renommé, nous nous rendons dans la fenêtre des propriétés :
Maintenant, nous pouvons créer simplement des propriétés dans le module de classe en utilisant le mot-clé Public :
Option Explicit
Public prenom As String
Public age As Integer
Nous venons simplement les déclarer dans le module de classe pour pouvoir les utiliser en tant que propriété du futur objet.
De retour dans la macro, nous pouvons enfin déclarer un nouvel objet en utilisant la classe personnalisée nouvellement créée :
Sub lesObjets()
Dim client(1 To 2) As New cClient
End Sub
La création de l’objet se fait donc en utilisant le mot-clé New.
Une fois l’objet déclaré, le reste de la macro va être exactement identique à la macro précédente, dans laquelle nous avions utilisé la variable personnalisée :
En revanche, les variables prenom et age, seront réservées à la classe personnalisée, et ne pourront pas être utilisées directement dans les autres modules.
L’utilisation du suffise Public permet ici de les rendre accessibles en tant que propriété de l’objet client !
Ce terme signifie en effet que nous pouvons utiliser la propriété en dehors du module de classe, mais pour autant, celui-ci reste une propriété dépendante de l’objet.
3. Création de propriétés
Dans la partie précédente, nous avons utilisé le terme de propriété pour définir les variables Public de la classe personnalisée.
Ce terme était en fait incorrect, il ne s’agit pas de propriété, mais de simples variables attribuées à la classe personnalisée.
Nous ne devrions même pas utiliser le suffixe Public comme nous l’avons vu dans le chapitre précédent !
En effet, les variables ne devraient pas être lisible depuis les autres modules, et devraient donc être privées :
Private pPrenom As String
Private pAge As Integer
Vous noterez au passage qu’il convient donc de renommer les variables, par exemple en ajoutant un suffixe (p pour propriété)
Dans ce cas, comment stocker des informations dans ces variables et y accéder par la suite ?
Tout simplement en créant des propriétés (de véritables cette fois-ci) auxquelles nous accédons en utilisant les assesseurs suivants :
- Get : permet de lire une valeur d’une propriété,
- Let : permet d’attribuer une valeur d’une propriété,
- Set : permet d’attribuer un objet
Une propriété donc peut être manipulée par un ou plusieurs assesseurs :
- La propriété sera en lecture seule, si le seul assesseur est le Get,
- Elle ne sera qu’en lecture si le seul assesseur est le Let ou le Set,
- Et elle sera accessible en lecture et en écriture si elle dispose de l’assesseur Get et de l’assesseur Let (ou Get si la propriété est un objet)
Par exemple, pour obtenir le prénom d’un client, nous allons utiliser la propriété :
Property Get Prenom() As String
Prenom = pPrenom
End Property
En d’autres termes, cette propriété permet de retourner la valeur enregistrée à la variable pPrenom dans l’instance de l’objet.
Bien entendu, pour pouvoir récupérer la valeur de la variable pPrenom en utilisant la propriété vue au-dessus, nous allons d’abord devoir lui en affecter une :
Property Let Prenom(sPrenom As String)
pPrenom = sPrenom
End Property
Il ne nous reste plus qu’à créer la propriété Age :
Property Get Age() As Integer
Age = pAge
End Property
Property Let Age(iAge As Integer)
pAge = iAge
End Property
Et maintenant, nous pouvons tester le code de la macro, celle-ci devrait fonctionner sans aucun changement !
4. Création de méthodes
Comme vous pouvez vous en douter, il est tout à fait possible de créer des méthodes directement dans le module de classe.
Pour cela, il suffit de créer une fonction, tout à fait classiquement à l’intérieur de ce module :
Sub nouvelleVente(montantVente As Long)
pVentes = pVentes + montantVente
End Sub
Puis d’appeler celle-ci comme nous l’avons fait pour les propriétés, c’est-à-dire en utilisant un point de séparation :
client(1).nouvelleVente 10000
Ici, nous ajoutons simplement une vente de 10000 euros sur le client 1, ce qui aura pour effet de le faire passer de la catégorie Bronze à Argent :
Pour le second exemple, nous allons tout simplement remettre le compteur à zéro (en imaginant par exemple que celui-ci à utiliser les avantages liés à sa carte de fidélité) :
Sub RAZ()
pVentes = 0
End Sub
5. Quel est l’intérêt des classes personnalisées ?
À ce moment-là de la découverte de la création des classes personnalisées, vous vous demandez surement quel peut être l’intérêt de se compliquer autant la vie pour finalement peu d’intérêt.
Et c’est justement à ce moment-là que nous allons découvrir toute la puissance des objets !
Maintenant, plutôt que de vouloir obtenir l’âge des personnes, imaginons que nous souhaitions analyser le montant des ventes réalisées.
Pour cela, nous allons commencer par créer une nouvelle propriété :
Private pVentes As Long
…
Property Get Ventes() As Long
Ventes = pVentes
End Property
Property Let Ventes(iVentes As Long)
pVentes = iVentes
End Property
Que nous allons ensuite pouvoir renseigner dans la macro le montant des ventes correspondantes :
Puis, nous allons pouvoir créer de manière totalement automatique une nouvelle propriété qui va permettre de classer les clients en fonction du montant des ventes réalisées :
Private pRang As String
…
Property Get Rang() As String
If pVentes > 30000 Then
Rang = "Client Gold"
ElseIf pVentes > 15000 Then
Rang = "Client Argent"
ElseIf pVentes > 5000 Then
Rang = "Client Bronze"
Else
Rang = "Nouveau client"
End If
End Property
Ici, pas besoin de propriété Let, le rang du client est généré automatiquement !
Nous pouvons maintenant l’afficher sans qu’aucune manipulation ne soit nécessaire :
Nous pourrions également imaginer modifier la propriété Prenom pour s’assurer que la casse soit correcte (c’est-à-dire la première lettre en majuscule, les autres en minuscule) :
Property Let Prenom(sPrenom As String)
pPrenom = StrConv(sPrenom, vbProperCase)
End Property
De cette manière, peu importe la manière dont nous saisissons le prénom, celui-ci sera stocké sous la casse « Nom propre » :
En plus de cela, nous allons pouvoir gérer nos propres erreurs personnalisées lorsque l’utilisateur va saisir une donnée erronée.
Pour cela, nous allons effectuer les tests nécessaires directement au niveau de l’affectation de la propriété, et lorsqu’une anomalie est détectée, nous pouvons générer l’erreur en utilisant l’objet VBA Err que nous avons découvert dans le chapitre précédent de la formation sur l’apprentissage de VBA pour les débutants :
Property Let Prenom(sPrenom As String)
If sPrenom = "" Then
Err.Raise vbObjectError + 468, "cClient.Prenom", "Prénom invalide"
Else
pPrenom = StrConv(sPrenom, vbProperCase)
End If
End Property
Ici, nous avons demandé à VBA de nous retourner un numéro d’erreur automatique, en dehors de la plage réservée (en utilisant vbObjectError), puis nous précisons à quel endroit se trouve l’erreur et enfin, une rapide description de celle-ci, qui nous aidera ensuite à debugger le code :
6. L’explorateur d’objets
Pour nous aider à coder des macro-commandes en utilisant les objets (qu’il s’agisse de nos propres créations, ou même des objets intégrés à VBA), nous avons à notre disposition deux outils :
- L’assistant à la saisie,
- Et l’explorateur de projet
Nous avons déjà eu l’occasion de découvrir le premier.
Il s’agit en effet des suggestions proposées par VBE au fil de la saisie dans une petite infobulle
Il suffit alors de saisir le nom de l’objet désiré, et lorsque nous tapons le point, Excel affiche les différentes propriétés de l’objet, que nous pouvons sélectionner simplement en cliquant dessus, ou encore à l’aide des flèches de direction.
Le second outil que nous allons découvrir ici est quant à lui spécifiquement dédié à l’étude des objets, il s’agit comme nous venons de le voir de l’explorateur d’objets.
Pour l’afficher, rendons-nous dans le menu Affichage > Explorateur d’objets (pour aller plus vite, il est également possible d’utiliser le raccourci clavier [F2]) :
Nous retrouvons alors dans cette fenêtre tous les objets du projet :
- Les objets qui permettent à VBA de fonctionner, tels que Worksheets, Range, …
- Nos propres objets créés dans des modules de classe personnalisés
Pour chacun de ces objets nous allons retrouver une description des méthodes, propriétés et des variables (et également des évènements, mais cela nous le découvrirons dans un prochain chapitre).
Pour consulter un objet et l’ensemble de ces éléments, il suffit tout simplement que cliquer sur celui-ci :
Sur la partie droite, nous retrouvons alors tous les membres de l’objet et nous pouvons cliquer sur l’un d’entre eux pour en visionner le détail dans la partie basse de l’interface :
Nous retrouvons alors les arguments attendus par la propriété, ainsi que le type (par exemple, la propriété Address de l’objet Range va nous retourner les coordonnées des cellules concernées sous la forme d’une chaîne de caractères).
Nous pouvons également savoir si la propriété sera accessible en lecture seulement, en écriture ou alors en lecture et en écriture.
Enfin, nous pouvons immédiatement la dernière information présentée nous montre le lien de hiérarchie entre le membre sélectionné et les différents éléments parents dont il dépend
Pour accéder directement à l’objet voulu, il est possible d’utiliser le champ de recherche dédie, qui se situe en haut de la fenêtre :
Celui-ci sera sélectionné, et nous retrouverons tous les éléments qui le compose dans la zone dédiée :
Si la recherche retourne plusieurs résultats, ceux-ci seront retournés dans la zone Résultats de la recherche :
Les dernières recherches effectuées au cours de la session (c’est-à-dire depuis le lancement du projet) sont retournés dans le menu déroulant :
La fenêtre d’exploration d’objet permet également de retrouver rapidement les différentes constantes présentes dans le projet.
Nous pouvons par exemple retrouver les constantes de direction (xlDown, xlToLeft, xlToRight et xlUp) réunies dans la classe XlDirection :
Nous voyons alors que la constante XlDown a pour valeur -4121.
Et voilà, c’est tout pour ce qui concerne les classes personnalisée… du moins pour le moment ! Dans un prochain chapitre nous découvrirons la notion évènement de VBA, et nous verrons alors qu’il est possible d’automatiser des actions directement pour nos objets !