La gestion des boucles dans Excel
Date de publication : 19/08/2007 , Date de mise à jour : 26/11/2007
Par
SilkyRoad (silkyroad.developpez.com)
Cet article présente différents types de boucles utilisables dans Excel.
Testé avec Excel2002 et 2007.
I. Introduction
II. For Each Next
III. For Next
IV. Do Loop
V. While Wend
VI. Les boucles récursives
VII. Arrêter une boucle
VIII. Conclusion
IX. Remerciements
X. Téléchargement
I. Introduction
En programmation, une boucle, aussi appelée itération, permet d'effectuer une série d'actions de
façon répétitive.
Il existe plusieurs solutions pour créer une boucle:
* For Each Next: Boucle sur chaque objet d'une collection.
* For Next: Répète une action le nombre de fois spécifié
par un compteur.
* Do Loop: Itération pendant ou jusqu'à ce qu'une
condition soit remplie.
* While Wend: Répète une action tant qu'une condition est vraie.
* Boucle récursive: Crée une procédure qui s'appelle
elle-même pendant ou jusqu'à ce qu'une condition soit remplie.
II. For Each Next
Ce type de boucle peut être traduit par:
|
Pour chaque [élément] d'un [Ensemble]
Série d'actions
[élément] suivant
|
Ici, [Ensemble] représente une collection.
L'architecture Excel est construite sous forme d'objets et de collections.
C'est pour cette raison que le langage Visual Basic For Applications (VBA) est dit 'orienté objet'.
Chaque collection possède des objets qui peuvent eux mêmes contenir d'autres collections:
L'application possède une collection de classeurs.
Chaque classeur possède une collection de feuilles.
Chaque feuille peut contenir une collection de graphiques incorporés.
... etc ...
Dans ce schéma, issu de l'aide Excel 2002, L'objet Application
représente le niveau le plus élevé.
Les éléments en bleu sont des objets.
Les éléments en jaune peuvent contenir des objets ou des collections.
Le principe de fonctionnement de l'instruction
For Each Next va donc consister à boucler sur tous
les objets d'une collection spécifique. Si la collection ne contient par d'objet ou quand tous les
objets ont été parcourus, la boucle est fermée et l'exécution continue sur la ligne de code,
juste après l'instruction
Next.
Ce premier exemple boucle sur les classeurs ouverts dans l'application Excel:
| Vba |
Sub BoucleClasseurs()
Dim Wb As Workbook
For Each Wb In Application.Workbooks
Debug.Print Wb.Name
Next Wb
End Sub
|
Vous noterez que Workbooks représente la collection de tous les classeurs,
et Workbook définit un objet de cette collection pour chaque itération.
D'une manière générale en VBA, le nom des collections est différencié du nom d'objets par un s
placé à la fin: Worksheets/Worksheet, ChartObjects/ChartObject ... etc ...
En reprenant le schéma vu précédemment, il est possible des créer des boucles imbriquées qui vont
descendre jusqu'au niveau de détail le plus fin.
Ce nouveau code intervient sur la plage de cellules A1:A10, dans toutes les feuilles de tous
les classeurs ouverts:
| Vba |
Sub BouclePlagesCellules()
Dim Wb As Workbook
Dim Ws As Worksheet
Dim Cell As Range
For Each Wb In Application.Workbooks
For Each Ws In Wb.Worksheets
For Each Cell In Ws.Range("A1:A10")
If Cell.Value = 3 Then Cell.Value = Cell.Value * 2
Next Cell
Next Ws
Next Wb
End Sub
|
Ce n'est pas une obligation pour le bon fonctionnement de la procédure, mais vous remarquez
que chaque instruction
Next est suivie du nom de la variable objet (Next Wb, Next Ws, Next Cell).
Cette règle d'écriture améliore la relecture des codes volumineux et contenant de nombreuses boucles
imbriquées.
De même, utilisez l'indentation (décalage des portions de macro par l'insertion de tabulations)
pour améliorer la lisibilité du code.
Pour gérer la sortie anticipée d'une boucle, utilisez l'instruction
Exit For. Dans ce cas
la procédure passe directement à la ligne de code qui suit l'instruction
Next.
L'instruction
Exit For peut être utilisée:
* Après la vérification d'une condition.
*
Lorsqu'une erreur se produit.
Exemple:
| Vba |
Sub BoucleFeuilles()
Dim Ws As Worksheet
For Each Ws In ThisWorkbook.Worksheets
If Ws.Name = "Feuil2" Then Exit For
MsgBox Ws.Name
Next Ws
End Sub
|
III. For Next
Ce type de boucle peut être traduit par:
|
De [Compteur] = [Numéro de départ] à [Numéro d'arrivée]
Série d'actions
[Compteur] suivant
|
L'instruction For Next permet de répéter des actions un nombre de fois prédéfini.
Vous devez spécifier une valeur de début [Numéro de départ] et une valeur de fin [Numéro d'arrivée].
La variable [compteur] va ensuite être incrémentée ou décrémentée à chaque itération.
| Vba |
Sub Test_V01()
Dim x As Integer
For x = 3 To 10
Cells(x, 1) = "Ligne " & x
Next x
End Sub
|
Par défaut, le compteur est incrémenté d'une unité positive à chaque itération.
Ajoutez l'argument Step afin de personnaliser le pas d'incrémentation. Cette valeur peut être
positive ou négative.
Une fois que toutes les actions spécifiées dans la boucle sont terminées, la valeur de
l'argument Step est ajoutée à la variable [compteur].
La boucle s'exécute tant que la valeur [compteur] est inférieure ou égale à la valeur de
fin [Numéro d'arrivée].
| Vba |
Sub Test_V02()
Dim x As Integer
For x = 3 To 10 Step 3
Cells(x, 1) = "Ligne " & x
Next x
End Sub
|
L'indication d'une valeur négative pour l'argument Step, permet de décrémenter le compteur
de la valeur la plus élevée vers la valeur la plus basse.
Vous devez spécifier une valeur de fin [Numéro d'arrivée] inférieure à la valeur de début
[Numéro de départ].
La boucle s'exécute tant que la valeur [compteur] est supérieure ou égale à la valeur de
fin [Numéro d'arrivée].
| Vba |
Sub Test_V03()
Dim x As Integer
For x = 10 To 3 Step -3
Cells(x, 1) = "Ligne " & x
Next x
End Sub
|
Nota:
Lorsque vous utilisez l'argument
Step pour décrémenter un compteur, le type de variable
(x dans les exemples précédents) ne doit pas être
Byte, sinon vous obtiendrez un message
d'erreur 'Dépassement de capacité'.
Pour gérer la sortie anticipée d'une boucle, avant que le compteur n'atteigne la valeur de fin,
utilisez l'instruction
Exit For. Tout comme dans le type de boucle
For Each Next,
la procédure passe directement à la première ligne de code qui suit l'instruction
Next.
L'instruction
Exit For peut être utilisée:
* Après la vérification d'une condition.
*
Lorsqu'une erreur se produit.
Exemple:
| Vba |
Sub Test_V04()
Dim x As Integer
For x = 1 To 10
If Not IsNumeric(Cells(x, 1)) Then Exit For
Cells(x, 1) = Cells(x, 1) * 2
Next x
End Sub
|
Vous pouvez bien entendu créer des boucles imbriquées et associer dans une même procédure
les instructions For Next et For Each Next.
| Vba |
Sub TestBouclesImbriquees()
Dim Ws As Worksheet
Dim x As Integer, y As Integer
For Each Ws In ThisWorkbook.Worksheets
For x = 1 To 10
For y = 1 To 7 Step 2
Ws.Cells(x, y) = "L" & x & "-C" & y
Next y
Next x
Next Ws
End Sub
|
Bien que ce ne soit pas toujours conseillé, car cela complique la relecture du code, il est possible de
modifier la valeur du compteur pendant les instructions de la boucle, entre chaque incrémentation.
Exemple pour extraire les valeurs numériques dans une chaîne de caractères:
| Vba |
Sub extraireValeursNumeriques_DansChaine()
Dim x As Integer, Nb As Integer
Dim Cible As String, Resultat As String
Dim Nombre As Single
Cible = "12,3azerty23,5 67"
Cible = Replace(Cible, ",", ".")
Cible = Replace(Cible, " ", "$")
For x = 1 To Len(Cible)
If IsNumeric(Mid(Cible, x, 1)) Then
Nombre = Val(Mid(Cible, x, Len(Cible) - x + 1))
Nb = Nb + 1
Resultat = Resultat & Nombre & vbLf
x = x + Len(Str(Nombre)) - 1
End If
Next
MsgBox "Il y a " & Nb & " valeurs numériques dans la chaîne:" & vbLf & Resultat
End Sub
|
IV. Do Loop
Les boucles Do Loop, associées aux mots clés While et Until permettent de
répéter une ou plusieurs actions pendant ou jusqu'à ce qu'une condition soit remplie.
Les instructions peuvent être associées de différentes manières:
Do
Actions
Loop While condition
Qui peut être traduit par:
|
[Faire]
Les actions à effectuer
[Recommencer] [Tant que] condition
|
Do While condition
Actions
Loop
Qui peut être traduit par:
|
[Faire] [Tant que] condition
Les actions à effectuer
[Recommencer]
|
Do Until condition
Actions
Loop
Qui peut être traduit par:
|
[Faire] [Jusqu'à ce que] condition
Les actions à effectuer
[Recommencer]
|
Do
Actions
Loop Until condition
Qui peut être traduit par:
|
[Faire]
Les actions à effectuer
[Recommencer] [Jusqu'à ce que] condition
|
Vous pouvez utiliser les mots clés While et Until pour vérifier qu'une condition est
remplie:
* Avant d'exécuter les actions contenues dans la boucle.
* Après chaque exécution de la boucle.
Do Loop peut exécuter des blocs d'instructions un nombre de fois indéfini.
Il est donc important de s'assurer qu'une condition de sortie pourra être remplie et que la
boucle ne tournera pas sans fin.
Dans cet exemple, la boîte de dialogue s'affiche tant que le mot de passe saisi est
incorrect:
| Vba |
Sub SaisieMotDePasse()
Dim Reponse As String
Do While Reponse <> "mimi"
Reponse = InputBox("Saissez le mot de passe:", "Mot de passe")
Loop
MsgBox "OK, poursuite de la procédure."
End Sub
|
Cette autre procédure incrémente la variable "i" d'une unité à chaque itération, permettant ainsi
de boucler sur les cellules de la colonne A jusqu'à trouver la chaîne "DVP".
| Vba |
Sub Boucle_V01()
Dim i As Integer
Do
i = i + 1
Loop While Cells(i, 1) <> "DVP"
MsgBox "Trouvé ligne " & i
End Sub
|
Bien évidemment, si le mot "DVP" n'existe pas, la procédure ne va jamais s'arrêter. Pour y remédier
vous pouvez ajouter l'instruction Exit Do qui permet d'anticiper la sortie de la boucle.
Voici une modification de la macro précédente afin de ne pas dépasser 1000 itérations, si le mot
recherché n'est pas trouvé.
| Vba |
Sub Boucle_V02()
Dim i As Integer
Do
i = i + 1
If i > 1000 Then Exit Do
Loop While Cells(i, 1) <> "DVP"
MsgBox IIf(Cells(i, 1) = "DVP", "Trouvé ligne " & i, "Pas trouvé")
End Sub
|
Tout comme dans les autres méthodes, il est possible de créer des boucles imbriquées.
Voici une adaptation de l'exemple précédent (On sort de la procédure après 1000 itérations si
le mot recherché n'est pas trouvé dans la colonne A):
| Vba |
Sub Boucle_V03()
Dim Trouve As Boolean
Dim x As Integer
Trouve = False
Do
Do While x < 1000
x = x + 1
If Cells(x, 1) = "DVP" Then
Trouve = True
Exit Do
End If
Loop
Loop Until Trouve = True Or x = 1000
MsgBox IIf(Trouve = True, "Trouvé ligne " & x, "Pas trouvé")
End Sub
|
Do Loop est aussi parfois utilisée tant qu'un évènement
est ou n'est pas survenu.
Cet exemple attend la fin de chargement d'une page html avant de poursuivre la procédure
(Toutefois il est toujours préférable, quand c'est possible, d'utiliser les évènements spécifiques
de l'application: DocumentComplete dans ce cas).
| Vba |
Sub piloterPageHtml()
Dim IE As Object
Dim T As Single
T = Timer
Set IE = CreateObject("internetExplorer.Application")
IE.Visible = True
IE.navigate "http://office.developpez.com/"
Do Until IE.readyState = 4
DoEvents
Loop
Debug.Print "Page chargée en " & (Timer - T) & " secondes."
End Sub
|
V. While Wend
L'instruction While Wend répète une action tant qu'une condition est vraie.
While condition
Actions
Wend
Qui peut être traduit par:
|
[Tant que] La condition à vérifier
Les actions à effectuer
[Répéter]
|
Si la condition est vraie, les actions indiquées dans la procédure sont effectuées.
Quand l'instruction Wend est atteinte, la procédure revient sur l'instruction While
et la condition est de nouveau vérifiée.
Si condition est toujours vraie, le processus est répété.
Si la condition est fausse, l'exécution passe directement à la première ligne de code
qui suit l'instruction Wend.
| Vba |
Sub Test_WhileWend()
Dim i As Integer
i = 1
While Not IsEmpty(Cells(i, 1))
Debug.Print Cells(i, 1)
i = i + 1
Wend
End Sub
|
Remarque:
While Wend est incluse dans VBA pour assurer une compatibilité ascendante.
Privilégiez l'instruction Do Loop qui permet d'exécuter une itération de manière plus structurée
et plus souple (CF aide Excel).
La méthode While wend ne possède pas d'instruction spécifique pour la sortie anticipée
de boucle.
VI. Les boucles récursives
Une procédure est dite
récursive lorsqu'elle s'appelle elle-même.
Cette technique a des avantages mais peut aussi poser des problèmes d'espace mémoire
(De la mémoire supplémentaire est utilisée à chaque fois qu'une procédure s'appelle elle-même).
Une condition de sortie est également nécessaire afin de terminer la fonction récursive sinon elle peut
boucler sur elle-même à l'infini.
Faites toujours vos premiers tests en mode pas à pas afin de vous assurer:
* Que la condition de sortie peut être remplie.
* Que la répétition des appels récursifs n'épuise pas l'espace mémoire
disponible.
Pour optimiser les ressources mémoire:
* Faites le ménage dans vos codes: Supprimez les variables inutiles.
*
Adaptez correctement les types de données.
* Evitez d'utiliser les types de données Variant.
* Vérifiez la structure de la procédure.
Vérifiez toujours préalablement si la récursivité ne peut pas être remplacée par des boucles imbriquées.
Cet exemple utilise la récursivité pour boucler sur le répertoire spécifié et tous ses
sous-répertoires, afin de lister le nom des fichiers qu'ils contiennent.
| Vba |
Option Explicit
Sub TestListeFichiers()
Dim Dossier As String
Dossier = "C:\Documents and Settings\mimi\dossier"
ListeFichiers Dossier
Columns("A:E").AutoFit
MsgBox "Terminé"
End Sub
Sub ListeFichiers(Repertoire As String)
Dim Fso As Scripting.FileSystemObject
Dim SourceFolder As Scripting.Folder
Dim SubFolder As Scripting.Folder
Dim FileItem As Scripting.File
Dim i As Long
Set Fso = CreateObject("Scripting.FileSystemObject")
Set SourceFolder = Fso.GetFolder(Repertoire)
i = Range("A65536").End(xlUp).Row + 1
For Each FileItem In SourceFolder.Files
Cells(i, 1) = FileItem.Name
ActiveSheet.Hyperlinks.Add Anchor:=Cells(i, 1), _
Address:=FileItem.ParentFolder & "\" & FileItem.Name
Cells(i, 2) = FileItem.DateCreated
Cells(i, 3) = FileItem.DateLastAccessed
Cells(i, 4) = FileItem.DateLastModified
Cells(i, 5) = FileItem.ParentFolder
i = i + 1
Next FileItem
For Each SubFolder In SourceFolder.subfolders
ListeFichiers SubFolder.Path
Next SubFolder
End Sub
|
VII. Arrêter une boucle
Dans les chapitres précédents, nous avons vu les instructions Exit For et Exit Do pour
forcer la sortie d'une boucle en fonction de conditions. Néanmoins, il y a toujours un risque de créer
une boucle infinie si la condition de sortie n'est jamais remplie.
En cas d'urgence, si une macro de veut plus s'arrêter, utilisez simultanément les touches
clavier: Ctrl + Pause.
Vous pouvez aussi utiliser la touche Echap.
Cette solution affiche une fenêtre d'erreur 'Exécution interrompue'. Cliquez sur le bouton
Fin pour terminer la procédure.
Si vous souhaitez gérer les touches Ctrl + Pause ou Echap par macro,
utilisez la propriété EnableCancelKey:
Cet exemple affiche un message personnalisé à la place de la fenêtre d'erreur, avant de sortir
de la macro.
| Vba |
Sub GestionSortieBoucle_Echap()
Dim x As Long
On Error GoTo Fin
Application.EnableCancelKey = xlErrorHandler
For x = 1 To 50000
Cells(x, 1) = x
Next x
Fin:
If Err.Number = 18 Then MsgBox "Opération annulée."
End Sub
|
VIII. Conclusion
La répétition d'actions va entrainer une durée de traitement plus ou moins longue en fonction:
* Du type de boucle.
* Du nombre d'itérations.
* De la logique et de la structure de votre code.
* De l'espace mémoire utilisé.
Avant d'utiliser une boucle, vérifiez qu'Excel ne dispose pas d'outils
spécifiques qui peuvent être appliqués en lieu et place dans votre projet.
Par exemple, pour supprimer tous les graphiques incorporés d'une feuille, plutôt
que de boucler sur les objets, il est possible d'utiliser directement:
| Vba |
Feuil1.ChartObjects.Delete
|
Il convient de Choisir le type de boucle le mieux adapté à votre projet.
Faites des essais pour mesurer le temps d'exécution dans différentes configurations et en testant
différentes méthodes.
Assurez vous qu'il existe au moins une condition qui permettra de terminer la boucle.
Si vous n'avez pas besoin de modifier directement les informations dans le classeur,
l'utilisation des
variables tableaux
sera la méthode la plus rapide pour traiter des grands groupes de données.
Boucler sur une collection sera (généralement) plus rapide que d'utiliser un compteur.
Evitez, quand c'est possible, les boucles récursives.
Utilisez des types de données
adaptés au contenu de chaque variable.
Evitez les variables
Variant qui sont moins rapides à traiter et nécessitent plus d'espace
mémoire.
La structure du code entre 2 itérations a aussi sont importance:
* Evitez au maximum les
Select et
Activate qui prennent
beaucoup de temps.
* Désactivez la mise à jour de l'écran.
* Désactivez si besoin le recalcul automatique (N'oubliez pas de le
réactiver en fin de procédure).
* Utilisez les sorties anticipées
Exit For et
Exit Do
pour ne pas continuer une boucle alors que toutes les actions sont terminées.
IX. Remerciements
Je remercie toute l'équipe Office, et particulièrement
Starec
pour la relecture et la correction du tutoriel.
X. Téléchargement


Les sources présentées sur cette page sont libres de droits,
et vous pouvez les utiliser à votre convenance.
Par contre, la page de présentation constitue une
oeuvre intellectuelle protégée par les droits d'auteurs.
Copyright ©
2007
Developpez LLC. Tous droits réservés Developpez LLC.
Aucune reproduction, même partielle, ne peut être faite de ce site et
de l'ensemble de son contenu : textes, documents et images sans l'autorisation
expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à 3 ans
de prison et jusqu'à 300 000 E de dommages et intérêts.
Cette page est déposée à la
SACD.