I. Introduction▲
I-A. Word, Macros, VBA et WordBasic▲
Word offre un outil puissant qui vous permet d'enregistrer des macros, c'est-à-dire des séquences d'actions servant à automatiser vos tâches habituelles ou
répétitives.
L'enregistreur de macros enregistre les déplacements du curseur pour positionner le point d'insertion et définir la zone de travaiL. Lors de son exécution, la
macro va refaire les mêmes actions y compris les déplacements. Cette manière de faire provient de la manière dont l'outil a été conçu. Initialement, Word est
un traitement de texte et l'utilisateur l'utilise pour créer et modifier un document, il est naturel que l'utilisateur puisse voir l'endroit sur lequel il agit
pour visualiser son travail et donc la majorité des actions consiste soit à ajouter, supprimer des caractères soit à appliquer des actions sur le texte sélectionné.
Et historiquement, le langage de Word de macro (WordBasic) est un langage qui offre un jeu d'instructions qui miment ce fonctionnement et donc l'enregistreur de
macros fournissait du code compatible avec ce fonctionnement. Par exemple, si vous déplaciez le point d'insertion de 5 caractères vers la droite, l'instruction
WordBasic est "CharRight 5". On comprend que le langage Wordbasic (comme la plupart des langages de l'époque d'ailleurs) est essentiellement procédural :
une instruction représente l'éxecution d'une action. L'arrivée des langages orientés objet a modifié le principe de programmation : on modifie des propriétés
des objets grâce à des services qu'ils proposent. Prenons un exemple pour comprendre, en Wordbasic, pour passer le 1er mot d'un texte en gras, le programme va être :
DébutDocument
MotDroite 1
, 1
Gras
soit pour un version anglaise
tartOfDocument
WordRight 1
, 1
Bold
Ce qui donne en VBA par l'enregistreur de macro
Selection.
HomeKey
Unit:=
wdStory
Selection.
MoveRight
Unit:=
wdWord, Count:=
1
, Extend:=
wdExtend
Selection.
Font
.
Bold
=
wdToggle
On voit qu'on reste proche, voire très proche : on utilise l'objet Sélection pour travailler comme en WordBasic mais le code correct en VBA s'écrit
ActiveDocument.
Words
(1
).
Bold
=
True
On voit qu'on a modifié la propriété du 1er mot mais on n'avait pas besoin de le sélectionner. Attention, ceci est un exemple choisi, tout, hélàs ne se passe pas de cette façon, loin de là. Mais c'est le principe.
I-B. Enregistreur de macros▲
Cet enregistreur est très utile car il fournit une base du code à utiliser sans connaître l'ensemble des possibilités, y compris pour les plus experts d'entre
nous mais les actions enregistrées sont directement liées à votre document et l'enregistreur de macros ne permet pas de généraliser ces séquences et ne permet pas
de tout faire, en particulier l'enregistreur ne sait pas gérer les collections, les procédures ou les fonctions. De plus, l'enregistreur définit en général tous les
paramètres ce qui est souvent inutile.
Ce tutoriel décrit un ensemble de règles basées sur l'expérience personnelle de l'auteur pour transformer une macro enregistrée en code VBA en vue de la généraliser
pour en augmenter sa réutilisation.
I-C. Tutoriels de référence▲
Ce tutoriel nécessite que vous possédiez des notions essentielles sur Word et sur VBA. Vous pouvez vous référer à des tutoriels de base disponibles sur DVP :
- Initiation au VBA d'Office
- Syntaxe de VBA
- Fondamentaux des variables et des constantes en VBA ainsi que Les variables, durée de vie et portée en VBA
Pour plus d'informations sur l'utilisation de l'enregistreur de macros, vous pouvez vous référer à ce tutoriel sur DVP : Comment utiliser l'enregistreur de macros
N'oubliez pas d'utiliser l'aide en ligne de Word disponible avec <F1> sur Mac ou PC et bien sûr la section Word et VBA Word de Developpez.
Attention, les exemples dans ce tutoriel ont parfois été volontairement non optimisés pour présenter des exemples plus pédagogiques.
II. Utilisation de l'enregistreur de macros▲
II-A. Quand doit-on utiliser l'enregistreur de macros ?▲
La bonne réponse est à chaque fois que vous commencez une nouvelle macro. En effet, même si vous connaissez bien le langage VBA, la méthode la plus efficace consiste à commencer par enregistrer le plus d'actions possibles pour disposer d'une base fiable puis à la mettre au point avec l'éditeur VBA et enfin à la généraliser.
II-B. Exemple de travail▲
Sélectionnez le texte suivant, copiez-le et collez-le dans un document Word vierge puis sauvegardez-le sous un nom et dans un emplacement de travail que vous désirez
Exemple de text
Cet exemple de texte est fourni par Developpez.
com
pour illustrer le tutoriel de passage du code de macro à du VBA
Voici un exemple de texte dans Word
Ceci est un autre exemple de texte dans Word
Ceci est un 3ième exemple de texte dans Word
Lorem
ipsum
dolor
sit
amet,
consectetur
adipiscing
elit.
Sed
non
risus.
Suspendisse
lectus
tortor,
dignissim
sit
amet,
adipiscing
nec,
ultricies
sed,
dolor.
II-C. Faire passse le 1er paragraphe en centré, gras et souligné▲
Lancez l'enregistreur de macro et saisissez "DvpTitreEnr" comme nom de macro. Rappel : lorsque l'enregistreur de macros fonctionne, la souris ne peut pas être utilisée.
- Placez-vous au début du document en tapant <Ctrl>+<Début>
- Sélectionnez le 1er paragraphe du document (donc ici "Exemple de text") en tapant <Ctrl>+<Maj>+<Flêche vers le bas>
- Faites passer le paragraphe en centré
- Faites passer le texte en gras
- Faites passer le texte en souligné
- Ajoutez le "e" pour corriger le mot et passer de "text" à "texte"
Arrêtez l'enregistreur de macro, ouvrez les macros et sélectionnez "DvpTitreEnr" puis cliquez sur "Modifier". Vous obtenez le code suivant :
Sub
DvpTitreEnr
()
'
'
DvpTitreEnr
Macro
'
'
Selection.
HomeKey
Unit:=
wdStory
Selection.
MoveDown
Unit:=
wdParagraph, Count:=
1
, Extend:=
wdExtend
Selection.
ParagraphFormat
.
Alignment
=
wdAlignParagraphCenter
Selection.
Font
.
Bold
=
wdToggle
Selection.
Font
.
UnderlineColor
=
wdColorAutomatic
Selection.
Font
.
Underline
=
wdUnderlineSingle
Selection.
EndKey
Unit:=
wdLine
Selection.
TypeText
Text:=
"
e
"
End
Sub
Quelques explications
Selection.HomeKey Unit:=wdStory <=> on déplace le point d'insertion en début de document puisqu'on veut travailler sur le 1er paragraphe.
Selection.MoveDown Unit:=wdParagraph, Count:=1, Extend:=wdExtend <=> on sélectionne le 1er paragraphe (comme à la souris) en déplaçant le point d'insertion en fin d'un seul paragraphe en "appuyant" sur la touche "<Shift>".
Selection.ParagraphFormat.Alignment = wdAlignParagraphCenter <=> on passe la sélection (donc ici le 1er paragraphe) en paragraphe centré.
Selection.Font.Bold = wdToggle <=> on passe la sélection (donc ici le 1er paragraphe) en caractères gras s'ils ne le sont pas (ce qui est le cas ici) et en non-gras, s'ils l'étaient (mais nous on voulait passer en gras toujours) et donc si on applique une nouvelle fois la macro on repasse en normal (ce qui n'est pas ce qu'on veut, nous on veut du gras).
Selection.Font.UnderlineColor = wdColorAutomatic Selection.Font.Underline = wdUnderlineSingle <=> on passe la sélection (donc ici le 1er paragraphe) en caractères souligné avec la couleur par défaut.
Selection.EndKey Unit:=wdLine <=> on déplace le point d'insertion en fin de sélection donc on déselectionne et on passe en fin du 1er paragraphe.
Selection.TypeText Text:="e" <=> on ajoute la lettre "e" au niveau du point d'insertion et donc en fin du 1er paragraphe.
Un des principes du VBA est de ne pas utiliser l'objet Sélection qui déplace le point d'insertion mais d'utiliser les collections fournies par VBA Word.
Ces collections contiennent soit d'autres collections (on parle de hiérarchies) soit des objets directs. Ces collections sont très nombreuses et couvrent l'ensemble
de la structure de ce que Word offre :
- un document est composé de paragraphes, eux-mêmes composés de mots, eux-mêmes composés de cacaratères... (Documents > Paragraphs > Characters...)
- un tableau est composé de lignes, elles-mêmes composées de cellules... (Tables > Rows > Cells...)
Chaque collection et chaque objet possèdent des propriétés (<=> les valeurs de l'objet) et des méthodes (<=> des actions possibles pour interagir avec Word).
Attention, tous les objets manipulés par Word ne sont pas toujours représentés par des collections. Par exemple, un paragraphe contient des caractères qui sont soit des lettres, des chiffres, des espaces, soit des signes de ponctuation... mais les collections de lettres n'existent pas en tant que telles et donc il faut apprendre à connaître le modèle de Word pour manipuler correctement ces objets et ces collections.
Ici un des codes possibles pour réaliser cette fonction est le suivant :
Sub
DvpTitre
()
ActiveDocument.
Paragraphs
(1
).
Alignment
=
wdAlignParagraphCenter
ActiveDocument.
Paragraphs
(1
).
Range
.
Bold
=
True
ActiveDocument.
Paragraphs
(1
).
Range
.
Underline
=
wdUnderlineSingle
ActiveDocument.
Range
(Start:=
ActiveDocument.
Paragraphs
(1
).
Range
.
End
-
1
, End
:=
ActiveDocument.
Paragraphs
(1
).
Range
.
End
-
1
).
InsertAfter
"
e
"
End
Sub
Quelques explications
ActiveDocument.Paragraphs(1).Alignment = wdAlignParagraphCenter correspond à travailler sur le document courant "ActiveDocument",
à utiliser dans sa collections de paragraphs "Paragraphs" le 1er "(1)" puis à lui appliquer la mise en forme de paragraphes centré.
Jusque là c'est simple on utilise la même chose que la sélection sauf qu'on travaille directement sur l'objet concerné.
ActiveDocument.Paragraphs(1).Range.Bold = True pose le problème du fameux objet Range. Pour pouvoir travailler dans Word,
on peut manipuler les collections (cf. la ligne de code précédente) mais c'est très rare de le faire directement, il faut souvent passer un objet de manipulation
qui fait référence à une zone contiguë d'un document et cet objet en Word, c'est l'objet Range.
Par exemple, si vous désirez insérer une lettre en fin de paragraphe, vous vous dites que vous allez prendre la collection Paragraphs, prendre le 1er et
lui ajouter "e", ce qui est très légitime mais non. Comme Word est un logiciel basé sur une interface qui exécute des actions et qui déclenchent des événements qui
vont eux-mêmes pouvoir générer d'autres actions, il faut utiliser cet objet de manipulation. Ne vous inquiétez pas, il m'a fallu du temps pour le comprendre aussi.
En effet, l'ajout d'un caractère peut provoquer un changement de ligne, qui va lui même provoquer un changement de page et qui va provoquer la création d'un nouvel
entête/pied de page si vous étiez par exemple en début de section avec un 1ère page différente. L'ajout d'un simple retour chariot (<=> nouveau paragraphe)
peut provoquer une nouvelle pagination, renuméroter des titres, des légendes, provoquer des changements de page... On voit que ces actions en cascade ne peuvent pas
être un simple ajout dans une seule liste mais il faut bien demander à Word à faire la même chose que si on travaillait sur la sélection sauf qu'on veut travailler
irectement sur l'objet concerné et donc on utilise alors l'objet Range. Il faut bien comprendre ces différences entre d'un côté l'objet Sélection (en gros la souris
et/ou le clavier) et les collections et en VBA, pour simplifier, dites-vous que l'objet Range finalement fait le lien entre ces concepts différents.
Donc ici, on prend le 1er paragraphe du document (""ActiveDocument.Paragraphs(1)") et comme on veut lui appliquer une mise en forme (donc des actions
graphiques), on utilise l'objet Range qui détermine la zone de travail (ici la zone du 1er paragraphe) donc ".Range" et puis on applique la mise en forme
"gras" que l'on force ici à être toujours en gras (ce aque l'on voulait).
Ici, on va voir si l'utilisation du Range a été bien assimilée. On veut ajouter un caractère "e" en fin de parapagraphe. Le principe est donc :
ActiveDocument.Range(Start:=ActiveDocument.Paragraphs(1).Range.End - 1, End:=ActiveDocument.Paragraphs(1).Range.End - 1).InsertAfter "e".
II-D. Transformer les points du texte en paragraphes▲
Lancez l'enregistreur de macro et saisissez "DvpRechercherMultipleEnr" comme nom de macro.
- Placez-vous au début du document en tapant <Ctrl>+<Début>
- Effectuez une recherche sur "." suivi d'un espace
- Placez à la fin de la sélection
- Supprimez le caractère précédent et tapez un retour chariot <=> nouveau paragraphe
- Recommencez la recherche jusqu'à ce que vous soyez en fin de document
Rappel, les exemples dans ce tutoriel ont parfois été volontairement non optimisés pour présenter des exemples plus pédagogiques.
Ici un remplacement global aurait été une meilleure solution en Word. Mais ce n'est pas le sujet du tutoriel.
Arrêtez l'enregistreur de macro, ouvrez les macros et sélectionnez "DvpRechercherMultipleEnr" puis cliquez sur "Modifier". Vous obtenez le code suivant :
Sub
DvpRechercherMultipleEnr
()
'
'
DvpRechercherMultipleEnr
Macro
'
'
Selection.
HomeKey
Unit:=
wdStory
Selection.
Find
.
ClearFormatting
With
Selection.
Find
.
Text
=
"
.^w
"
.
Forward
=
True
.
Wrap
=
wdFindContinue
.
Format
=
False
.
MatchCase
=
False
.
MatchWholeWord
=
False
.
MatchWildcards
=
False
.
MatchSoundsLike
=
False
.
MatchAllWordForms
=
False
End
With
Selection.
Find
.
Execute
Selection.
MoveRight
Unit:=
wdCharacter, Count:=
1
Selection.
TypeBackspace
Selection.
TypeParagraph
Application.
Browser
.
Next
Selection.
MoveRight
Unit:=
wdCharacter, Count:=
1
Selection.
TypeBackspace
Selection.
TypeParagraph
Application.
Browser
.
Next
End
Sub
Quelques explications
Selection.HomeKey Unit:=wdStory <=> on déplace le point d'insertion en début de document puisqu'on veut travailler sur le 1er paragraphe.
Selection.Find.ClearFormatting <=> On purge les options de recherche.
With Selection.Find <=> Cette syntaxe permet d'éviter de dupliquer les mêmes débuts d'instructions jusqu'au prochain "End With".
.Text = ".^w"
.Replacement.Text = ".^p" <=> on remplace ".^w" par ".^p" c'est-à-dire tous les points suivis de n'importe quel type d'espace
par un point suivi par un nouveau paragraph (cf. tutoriel sur la recherche et le
remplacement dans Word).
.Forward = True <=> Définit le sens de la recherche ici vers le bas du document.
.Wrap = wdFindContinue <=> Définit si on s'arrête en fin de document ou si on reprend à partir du début ici on continue en fin de doc.
.Format = False <=> Définit si on utilise les options de formatage (gras/italique, couleur de caractères, police, titre...).
.MatchCase = False <=> Définit si la recherche est sensible à la casse ici on recherche indifférement sur les majuscules et les minusucles.
.MatchWildcards = False <=> Définit si la recherche utilise les caractères génériques ici on recherche sans caractère générique.
.MatchSoundsLike = False <=> Définit si la recherche est phonétique ici on recherche sans cet attribut.
.MatchAllWordForms = False <=> Définit si la recherche porte sur toutes les formes du mot ici on recherche sans cet attribut.
End With <=> Marque la fin de regroupement des instructions.
Selection.Find.Execute <=> On exécute la recherche.
Selection.MoveRight Unit:=wdCharacter, Count:=1 <=> On se déplace d'un caractère vers la droite. Mais ici on sait même pas si on a réussi à trouver le texte recherché.
Selection.TypeBackspace <=> On efface le caractère précédent. Attention, si on a trouvé, il n'y a pas de problème sinon on essaie d'effacer le caractère précédent mais n'importe lequel.
Selection.TypeParagraph <=> On insère un paragraphe.
Application.Browser.Next <=> On utilise l'explorateur pour déplacer le point d'insertion vers la prochaine occurrence de la recherche. Cet outil est accessible dans le bas de la barre de défilement verticale et permet de recherche la prochaine occurrence ou la suivante.
Selection.MoveRight Unit:=wdCharacter, Count:=1
Selection.TypeParagraph
Selection.TypeParagraph
Application.Browser.Next <=> cf. plus haut.
L'un des problèmes de l'enregistreur de macro est sa verbosité : il définit tous les paramètres y compris ceux par défaut et rend le code plus lourd donc
moins lisible. Vous pouvez les conserver, surtout si vous ne connaissez pas le fonctionnement d'un des paramètres, mais pour simplifier la macro, pensez à supprimer les
paramètres inutiles :
Pour cela, ne supprimez pas directement les instructions mais ajoutez une apostrophe simple au début de chaque ligne que vous voulez supprimer. Cet apostrophe est la
syntaxe pour mettre une ligne en commentaire (elle devrait changer de couleur dans l'éditeur). Ainsi la macro ne fonctionne plus comme vous vous y attendez, il suffit
de supprimer l'apostrophe pour retrouver le comportement et en plus sans avoir à ressaisir le code ou à ré-enregistrer la macro.
Ici pour l'exemple, on va mettre en commentaires tous les attributs de recherche inutiles (Format, MatchWholeWord, MatchWildcards, MatchSoundsLike, MatchAllWordForms)
Sub
DvpRechercherMultipleEnrModif1
()
'
'
DvpRechercherMultipleEnr
Macro
-
Version
modifiée
'
'
Selection.
HomeKey
Unit:=
wdStory
Selection.
Find
.
ClearFormatting
With
Selection.
Find
.
Text
=
"
.^w
"
.
Forward
=
True
.
Wrap
=
wdFindContinue
.
Format
=
False
'
.MatchCase
=
False
.
MatchWholeWord
=
False
'
.MatchWildcards
=
False
'
.MatchSoundsLike
=
False
'
.MatchAllWordForms
=
False
End
With
Selection.
Find
.
Execute
Selection.
MoveRight
Unit:=
wdCharacter, Count:=
1
Selection.
TypeBackspace
Selection.
TypeParagraph
Application.
Browser
.
Next
Selection.
MoveRight
Unit:=
wdCharacter, Count:=
1
Selection.
TypeBackspace
Selection.
TypeParagraph
Application.
Browser
.
Next
End
Sub
L'un des problèmes de l'enregistreur de macro est son impossibilité de gérer les tests des fonctions comme la recherche
Pour cela, après des fonctions comme la recherche, vous devez tester le résultat pour savoir si votre document correspond à ce qui est prévu dans votre code.
Ici pour l'exemple, on va mettre tester le résultat de la recherche avant d'effectuer les modifications. Le code pour vérfier si une recherche a abouti ou non est
"Selection.Find.Found" qui est valorisé à la valeur de la dernière recherche effectuée.
Vous avez remarquer que l'enregistreur de macros utilise l'instruction "With... End With", il décale le code : cette technique de codage, appelée "indentation",
plus ancienne que VBA, est très largement utilisée en technique de programmation et est reconnue comme facilitant la lecture et la compréhension du code. On va
donc continuer à l'utiliser et l'étendre à tous les blocs de programmation.
De façon identique, on va remplacer "Application.Browser.Next" qui relance la dernière recherche effectuée par une nouvelle exécution de la recherche mais comme
tous les paramètres de la recherche sont déjà positionnés, il suffit d'exécuter la dernière recherche <=> "Selection.Find.Execute"
Sub
DvpRechercherMultipleEnrModif2
()
Selection.
HomeKey
Unit:=
wdStory
Selection.
Find
.
ClearFormatting
With
Selection.
Find
.
Text
=
"
.^w
"
.
Forward
=
True
.
Wrap
=
wdFindContinue
.
Format
=
False
.
MatchWholeWord
=
False
End
With
Selection.
Find
.
Execute
If
Selection.
Find
.
Found
Then
Selection.
MoveRight
Unit:=
wdCharacter, Count:=
1
Selection.
TypeBackspace
Selection.
TypeParagraph
Selection.
Find
.
Execute
If
Selection.
Find
.
Found
Then
Selection.
MoveRight
Unit:=
wdCharacter, Count:=
1
Selection.
TypeBackspace
Selection.
TypeParagraph
End
If
End
If
End
Sub
Quelques explications
If Selection.Find.Found Then La commande "Selection.Find.Execute" positionne la varaible "Found" avec le résultat de la recheche
qui vaut "True" si la recherche a abouti (i.e. si on a trouvé l'élément recherché) sinon qui vaut "False".
Remarque : en programmation, on ne teste pas les expressions booléennes sur "True" ou sur "False" mais seulement sur leur condition <=> pas de
d'écriture "If Selection.Find.Found = True Then" mais bien "If Selection.Find.Found Then".
La deuxième instruction Selection.Find.Execute permet de relancer une nouvelle exécution de la recherche déjà définie.
VII. Remerciements▲
2Do