Je fais de la programmation VBA dans Excel 2007 et j'ai un classeur où toutes les fiches techniques doivent être copiées, dans une autre feuille. La nouvelle feuille aura plusieurs lignes d'en-tête, et je voudrais garder une trace de l'endroit où elles se trouvent afin de ne pas avoir à y trouver des mots en permanence.
La chose la plus simple est-elle d'utiliser des classes et de les faire fonctionner pendant que le document Excel est ouvert? Ou est-ce que cela le rendra lourd et difficile à gérer, et je devrais continuer à travailler avec des sous-programmes? Quels sont les avantages de l'utilisation des cours? Ce n'est pas comme si j'avais plusieurs objets, seulement des feuilles et une validation sur des colonnes.
L'avantage d'utiliser des classes au lieu de simplement des sous-programmes est que les classes créent un niveau d'abstraction qui vous permet d'écrire du code plus propre. Certes, si vous n'avez jamais utilisé de cours auparavant en VBA, il y a une courbe d'apprentissage, mais je pense que cela vaut certainement le temps de le comprendre.
Une indication clé que vous devez passer aux classes est si vous ajoutez constamment des paramètres à vos fonctions et sous-programmes. Dans ce cas, il est presque toujours préférable d'utiliser des classes.
J'ai copié une explication des classes de ne de mes précédentes réponses Stack Overflow :
Voici un long exemple de la façon dont l'utilisation d'une classe peut vous aider. Bien que cet exemple soit long, il vous montrera comment quelques principes de programmation orientée objet peuvent vraiment vous aider à nettoyer votre code.
Dans l'éditeur VBA, accédez à Insert > Class Module
. Dans la fenêtre Propriétés (en bas à gauche de l'écran par défaut), changez le nom du module en WorkLogItem
. Ajoutez le code suivant à la classe:
Option Explicit
Private pTaskID As Long
Private pPersonName As String
Private pHoursWorked As Double
Public Property Get TaskID() As Long
TaskID = pTaskID
End Property
Public Property Let TaskID(lTaskID As Long)
pTaskID = lTaskID
End Property
Public Property Get PersonName() As String
PersonName = pPersonName
End Property
Public Property Let PersonName(lPersonName As String)
pPersonName = lPersonName
End Property
Public Property Get HoursWorked() As Double
HoursWorked = pHoursWorked
End Property
Public Property Let HoursWorked(lHoursWorked As Double)
pHoursWorked = lHoursWorked
End Property
Le code ci-dessus nous donnera un objet fortement typé qui est spécifique aux données avec lesquelles nous travaillons. Lorsque vous utilisez des tableaux multidimensionnels pour stocker vos données, votre code ressemble à ceci: arr(1,1)
est l'ID, arr(1,2)
est le PersonName, et arr(1,3)
est le HoursWorked . En utilisant cette syntaxe, il est difficile de savoir ce qui est quoi. Supposons que vous chargez toujours vos objets dans un tableau, mais utilisez plutôt le WorkLogItem
que nous avons créé ci-dessus. Ce nom, vous pourriez faire arr(1).PersonName
pour obtenir le nom de la personne. Cela rend votre code beaucoup plus facile à lire.
Continuons avec cet exemple. Au lieu de stocker les objets dans un tableau, nous allons essayer d'utiliser un collection
.
Ensuite, ajoutez un nouveau module de classe et appelez-le ProcessWorkLog
. Mettez-y le code suivant:
Option Explicit
Private pWorkLogItems As Collection
Public Property Get WorkLogItems() As Collection
Set WorkLogItems = pWorkLogItems
End Property
Public Property Set WorkLogItems(lWorkLogItem As Collection)
Set pWorkLogItems = lWorkLogItem
End Property
Function GetHoursWorked(strPersonName As String) As Double
On Error GoTo Handle_Errors
Dim wli As WorkLogItem
Dim doubleTotal As Double
doubleTotal = 0
For Each wli In WorkLogItems
If strPersonName = wli.PersonName Then
doubleTotal = doubleTotal + wli.HoursWorked
End If
Next wli
Exit_Here:
GetHoursWorked = doubleTotal
Exit Function
Handle_Errors:
'You will probably want to catch the error that will '
'occur if WorkLogItems has not been set '
Resume Exit_Here
End Function
La classe ci-dessus va être utilisée pour "faire quelque chose" avec une colleciton de WorkLogItem
. Au départ, nous l'avons simplement configuré pour compter le nombre total d'heures travaillées. Testons le code que nous avons écrit. Créez un nouveau module (pas un module de classe cette fois; juste un module "normal"). Collez le code suivant dans le module:
Option Explicit
Function PopulateArray() As Collection
Dim clnWlis As Collection
Dim wli As WorkLogItem
'Put some data in the collection'
Set clnWlis = New Collection
Set wli = New WorkLogItem
wli.TaskID = 1
wli.PersonName = "Fred"
wli.HoursWorked = 4.5
clnWlis.Add wli
Set wli = New WorkLogItem
wli.TaskID = 2
wli.PersonName = "Sally"
wli.HoursWorked = 3
clnWlis.Add wli
Set wli = New WorkLogItem
wli.TaskID = 3
wli.PersonName = "Fred"
wli.HoursWorked = 2.5
clnWlis.Add wli
Set PopulateArray = clnWlis
End Function
Sub TestGetHoursWorked()
Dim pwl As ProcessWorkLog
Dim arrWli() As WorkLogItem
Set pwl = New ProcessWorkLog
Set pwl.WorkLogItems = PopulateArray()
Debug.Print pwl.GetHoursWorked("Fred")
End Sub
Dans le code ci-dessus, PopulateArray()
crée simplement une collection de WorkLogItem
. Dans votre code réel, vous pouvez créer une classe pour analyser vos feuilles Excel ou vos objets de données pour remplir une collection ou un tableau.
Le code TestGetHoursWorked()
montre simplement comment les classes ont été utilisées. Vous remarquez que ProcessWorkLog
est instancié en tant qu'objet. Après son instanciation, une collection de WorkLogItem
devient partie intégrante de l'objet pwl
. Vous le constatez dans la ligne Set pwl.WorkLogItems = PopulateArray()
. Ensuite, nous appelons simplement la fonction que nous avons écrite qui agit sur la collection WorkLogItems
.
Pourquoi est-ce utile?
Supposons que vos données changent et que vous souhaitiez ajouter une nouvelle méthode. Supposons que votre WorkLogItem
inclut maintenant un champ pour HoursOnBreak
et que vous souhaitez ajouter une nouvelle méthode pour le calculer.
Tout ce que vous devez faire est d'ajouter une propriété à WorkLogItem
comme ceci:
Private pHoursOnBreak As Double
Public Property Get HoursOnBreak() As Double
HoursOnBreak = pHoursOnBreak
End Property
Public Property Let HoursOnBreak(lHoursOnBreak As Double)
pHoursOnBreak = lHoursOnBreak
End Property
Bien sûr, vous devrez changer votre méthode de remplissage de votre collection (l'exemple de méthode que j'ai utilisé était PopulateArray()
, mais vous devriez probablement avoir une classe séparée juste pour cela). Ensuite, vous ajoutez simplement votre nouvelle méthode à votre classe ProcessWorkLog
:
Function GetHoursOnBreak(strPersonName As String) As Double
'Code to get hours on break
End Function
Maintenant, si nous voulions mettre à jour notre méthode TestGetHoursWorked()
pour retourner le résultat de GetHoursOnBreak
, tout ce que nous aurions à faire serait d'ajouter la ligne suivante:
Debug.Print pwl.GetHoursOnBreak("Fred")
Si vous avez transmis un tableau de valeurs qui représentait vos données, vous devriez trouver chaque endroit dans votre code où vous avez utilisé les tableaux, puis le mettre à jour en conséquence. Si vous utilisez des classes (et leurs objets instanciés) à la place, vous pouvez beaucoup plus facilement mettre à jour votre code pour travailler avec les modifications. De plus, lorsque vous autorisez la classe à être consommée de plusieurs manières (peut-être qu'une fonction n'a besoin que de 4 des propriétés des objets tandis qu'une autre fonction en aura besoin de 6), elles peuvent toujours référencer le même objet. Cela vous empêche d'avoir plusieurs tableaux pour différents types de fonctions.
Pour une lecture plus approfondie, je recommande fortement d'obtenir une copie de VBA Developer's Handbook, 2nd edition . Le livre est plein d'excellents exemples et de meilleures pratiques et des tonnes d'exemples de code. Si vous investissez beaucoup de temps dans VBA pour un projet sérieux, cela vaut la peine de regarder ce livre.
S'il y a beaucoup de sous-programmes ou si les sous-programmes sont très longs, la structuration du code en classes peut aider. S'il n'y a que quelques sous-programmes, disons, chacun ne contenant que 10 lignes de code, alors c'est fini. L'avantage de structurer le code en classes est qu'il est plus facile à lire et à modifier lorsque vous y revenez plus tard. Donc, une autre raison de structurer le code en classes est de savoir si le code a probablement besoin de changer sur la ligne
Il y a une autre chose que vous pourriez ajouter aux avantages que d'autres contributeurs ont déclarés (désolé si c'est quelque part dans l'excellente réponse de Ben McCormack et je l'ai ratée). Les classes peuvent avoir leur utilité si votre script VBA est susceptible d'être reprogrammé à un moment donné.
Par exemple, je conçois une sorte de système de gestion des commandes. Il doit être utilisé par plusieurs collègues pendant un certain temps, mais il peut être nécessaire de le reprogrammer si les règles de commande changent. J'ai donc conçu une classe de stock élémentaire, qui rassemble toutes les informations sur un stock. Les règles sur la façon dont ces données sont analysées pour tout ordre sont cependant écrites dans des sous-routines facilement accessibles et bien commentées. En faisant cela, j'espère que les futurs programmeurs VBA pourront facilement changer les règles mathématiques par lesquelles les commandes sont générées, sans avoir à gérer la façon dont toutes les données sont collectées sur un article en stock particulier (tout cela est fait par des sous-routines et des fonctions au sein de la classe , qui sont activés lorsque la classe reçoit un numéro de stock). Les propriétés publiques d'une classe sont également récupérées par intellisense, ce qui permet au prochain programmeur, ainsi qu'à vous-même, d'en profiter plus facilement.
Je suppose que le fait est que les classes peuvent rendre la vie plus facile aux utilisateurs ultérieurs de cette manière si ils codent un ensemble d'informations de base, ou un objet conceptuel, qui est toujours susceptible d'être pertinent dans le contexte de la utilisation du programme.