par , 22/04/2020 à 15h54 (1616 Affichages)
Salut.
Je vois souvent des codes événementiels qui font "plein de choses"... Pas sûr que ce soit une bonne pratique!
Dans ce billet, j'explique déjà pourquoi il ne faut jamais appeler du code événementiel, chose que je vois trop fréquemment sur le forum et qui est pour moi une mauvaise pratique. Un code événementiel ne peut être "appelé" que par l'événement considéré, sinon ce n'est plus du code événementiel. Certains ont déjà du mal à ce stade, apparemment.
Un code événementiel est un code qui s'exécute lorsqu'un événement survient dans l'application. Les événements les plus souvent utilisés, en VBA et dans Excel notamment, sont ceux qui surviennent à la suite d'une action de l'utilisateur (ouverture d'un fichier, activation d'un onglet, modification de la valeur d'une cellule, clic sur un bouton, ...). Il faut bien noter qu'un événement ne survient qu'avec des objets. Je ne vais pas lister ici tous les événements qui pourraient survenir, mais vous pouvez les détecter dans un module de classe, pour autant que la classe gère les événements.
A titre d'exemple, voici les événements que vous pouvez gérer dans une feuille de classeur
![Nom : 2020-04-23_075733.png
Affichages : 567
Taille : 41,5 Ko](https://www.developpez.net/forums/attachment.php?attachmentid=559287&d=1587621570)
Voici ceux que vous pouvez gérer pour un bouton de commande
![Nom : 2020-04-23_080017.png
Affichages : 519
Taille : 22,7 Ko](https://www.developpez.net/forums/attachment.php?attachmentid=559288&d=1587621663)
Ici, je vais simplement exposer le cas où, à l'ouverture d'Excel, on a besoin qu'un certain code soit utilisé. Comme exemple, je vais prendre le cas de devoir masquer toutes les feuilles sauf une*.
On pourrait programmer ainsi, et ça fonctionnerait fort bien:
1 2 3 4 5 6 7 8
| Private Sub Workbook_Open()
Dim sh As Object
Worksheets("Accueil").Visible = xlSheetVisible
For Each sh In Sheets
If sh.Name <> "Accueil" Then sh.Visible = xlSheetHidden
Next
End Sub |
Le problème va surgir lorsqu'il va falloir réaliser également d'autres tâches lors de l'ouverture, par exemple, récupérer le username de l'utilisateur pour afficher sur la feuille d'accueil certaines données le concernant et qui se trouvent dans une autre feuille du classeur. Voici l'événement adapté pour récupérer la liste des collaborateurs de l'utilisateur est l'afficher dans un tableau structuré sur la feuille d'accueil
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| Private Sub Workbook_Open()
Dim sh As Object
Dim r As Range
Dim User As String
Dim Target As Range
Worksheets("Accueil").Visible = xlSheetVisible
For Each sh In Sheets
If sh.Name <> "Accueil" Then sh.Visible = xlSheetHidden
Next
User = Environ("username")
If Not Range("t_MesCollaborateurs").ListObject.DataBodyRange Is Nothing Then _
Range("t_MesCollaborateurs").ListObject.DataBodyRange.Delete
For Each r In Range("t_Collaborateurs[Resp]")
If r.Value = User Then
Set Target = Range("t_Mescollaborateurs").ListObject.ListRows.Add().Range
Target.Value = r(1, 2).Value
End If
Next
End Sub |
Et là, notre code devient du code poubelle. On multiplie les variables au sein de la procédure, et pour peu que l'on ait un troisième "truc" à réaliser à l'ouverture, le code devient ingérable et une chatte n'y retrouverait pas ses jeunes...
Ce qu'il faut faire, pour utiliser une architecture professionnelle et ne pas coder comme un goret, c'est respecter la règle "une procédure = une responsabilité"... La procédure sur ouverture a la responsabilité d'appeler les procédures qui vont préparer le classeur, chaque procédure ayant une responsabilité propre.
Dès lors, dans un module standard, on devrait trouver les deux procédures suivantes:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| Sub ShowMenu()
Dim sh As Object
Worksheets("Accueil").Visible = xlSheetVisible
For Each sh In Sheets
If sh.Name <> "Accueil" Then sh.Visible = xlSheetHidden
Next
End Sub
Sub RetrieveStaff()
Dim r As Range
Dim User As String
Dim Target As Range
User = Environ("username")
If Not Range("t_MesCollaborateurs").ListObject.DataBodyRange Is Nothing Then _
Range("t_MesCollaborateurs").ListObject.DataBodyRange.Delete
For Each r In Range("t_Collaborateurs[Resp]")
If r.Value = User Then
Set Target = Range("t_Mescollaborateurs").ListObject.ListRows.Add().Range
Target.Value = r(1, 2).Value
End If
Next
End Sub |
La procédure événementielle à l'ouverture se réduit alors à ceci:
1 2 3 4
| Private Sub Workbook_Open()
ShowMenu
RetrieveStaff
End Sub |
Voilà, pour moi, comment on code proprement, en rendant son code compréhensible, maintenable, évolutif...
Bon travail avec Excel et VBA...
* J'écris ce billet en réaction aux "solutions" vues sur cette discussion.
Et vous, comment codez-vous vos évènements?