Vous êtes sur la page 1sur 11

Ajout d'un index thmatique dans Word en VBA

Par Jean-Franois Jousseaume (Sepia sur www.developpez.com)

Date de publication : 12 dcembre 2008

Cet article a pour but de vous montrer comment crer un index thmatique de Word en
VBA, l'aide d'un exemple d'un livre de cuisine, un autre de mes passetemps.
Attention, volontairement pour mettre en vidence des points prcis ou des lments
de code, cette macro n'est pas forcment optimise en temps de traitement.

Ajout d'un index thmatique dans Word en VBA par Jean-Franois Jousseaume (Sepia sur www.developpez.com)

1 - Introduction.............................................................................................................................................................3
2 - La gnration de l'index........................................................................................................................................ 4
2-A - Rappels......................................................................................................................................................... 4
2-B - Principe..........................................................................................................................................................5
2-C - Explications................................................................................................................................................... 5
2-D - Code complet de la macro........................................................................................................................... 8
2-E - Le fichier exemple.......................................................................................................................................11
3 - Remerciements.................................................................................................................................................... 11

-2Ce document est issu de http://www.developpez.com et reste la proprit exclusive de son auteur : Jean-Franois Jousseaume (Sepia sur www.developpez.com). La copie, modification et/ou
distribution par quelque moyen que ce soit est soumise l'obtention pralable de l'autorisation de l'auteur: Jean-Franois Jousseaume (Sepia sur www.developpez.com).

http://sepia.developpez.com/office/word/indexthematique/

Ajout d'un index thmatique dans Word en VBA par Jean-Franois Jousseaume (Sepia sur www.developpez.com)

1 - Introduction
Ce tutoriel dcrit comment crer ou mettre jour un index thmatique dans Word sur un exemple concret d'un
document comportant quelques bonnes pratiques d'utilisation : titres, styles, champs de formulaires, tableaux
corrects, table des matires, entte et pied de page, renvois, insertion d'images... autant d'lments qui posent des
problmes rcurrents aux DVPnautes.

Ce tutoriel s'appuie sur le document Word "DVP_Livre_Cuisine_Sepia.doc".


Le document est un extrait de 14 recettes de mon propre livre de cuisine qui contient une table des matires
standard bas sur des titres (cf. le tutoriel de Heureux-Oli sur les tables des matires)
Chaque recette est compose de la faon suivante :

un titre

un tableau dcrivant la catgorie du plat (entre chaude, plat, sauce...), l'estimation du cot (bon
march, modr, assez cher), l'estimation de la ralisation (facile, moyen, difficile), le temps de
prparation et de ralisation, les quantits (souvent je prend comme base 6 personnes) ainsi que
d'autres informations comme les mots-cls (Halloween, Nol, Anniversaire...), la date de la cration
de la recette et son ventuelle rfrence si j'ai mis la recette sur un blog (souvent sur marmiton) ou
la source si la recette provient de quelqu'un d'autre, les lgumes d'accompagnement (pour les plats),
le vin, les ustensiles, ces dernires rubriques tant assez rarement renseignes mais je prvois de le
faire (un jour). La dernire ligne du tableau est une liste de commentaires pour recueillir les impressions
et pour viter de refaire plusieurs fois le mme plat mes convives ou pour noter un ingrdient qu'ils
n'aiment pas.

la liste des ingrdients (dans le style "Ingrdients" - noir et italique)

la prparation (dans le style "Prparation" - en bleu)

la ralisation (dans le style "Recette" - en noir)

l'ventuelle finition (dans le style "Finition" - en orange)

des ventuelles astuces (dans le style "Astuce" - en noir avec un retrait et prcd d'une puce fabrique
partir d'une image GIF)

La recette peut comporter une variante qui apparat aussi dans la table des matires mais pas dans
l'index (pour que l'exemple soit plus dmonstratif)
Une table d'index secondaire base sur les catgories des recettes (apros, entres, plats, desserts...) est
cre partir d'une macro, dont je vais vous prsenter le fonctionnement. Cet index est repre par le signet
"TitreTableDIndexParCategorie"

Exemple de page du livre de recettes

-3Ce document est issu de http://www.developpez.com et reste la proprit exclusive de son auteur : Jean-Franois Jousseaume (Sepia sur www.developpez.com). La copie, modification et/ou
distribution par quelque moyen que ce soit est soumise l'obtention pralable de l'autorisation de l'auteur: Jean-Franois Jousseaume (Sepia sur www.developpez.com).

http://sepia.developpez.com/office/word/indexthematique/

Ajout d'un index thmatique dans Word en VBA par Jean-Franois Jousseaume (Sepia sur www.developpez.com)

2 - La gnration de l'index
2-A - Rappels
Pour les lments de base utiliss, se rfrer aux diffrents tutoriels de Heureux-Oli sur DVP.com

Numrotation des titres sous Word


Table des matires sous Word
Numrotation des pages sous Word
Enttes et pieds de page sous Word

-4Ce document est issu de http://www.developpez.com et reste la proprit exclusive de son auteur : Jean-Franois Jousseaume (Sepia sur www.developpez.com). La copie, modification et/ou
distribution par quelque moyen que ce soit est soumise l'obtention pralable de l'autorisation de l'auteur: Jean-Franois Jousseaume (Sepia sur www.developpez.com).

http://sepia.developpez.com/office/word/indexthematique/

Ajout d'un index thmatique dans Word en VBA par Jean-Franois Jousseaume (Sepia sur www.developpez.com)

2-B - Principe
La macro parcourt la table des matires entre par entre, chacune correspondant une recette, puis rcupre pour
chaque recette sa catgorie.
La macro vrifie alors si cette catgorie est dj prsente, si c'est le cas la recette est ajoute en fin de la liste des
recettes de cette catgorie sinon on cr la catgorie.
Lorsque la table des matires est entirement parcourue, on crit alors la table d'index par catgorie.
Remarque : Dans la plupart des langages informatiques, l'agrandissement d'un tableau est complexe et ne peut
s'effectuer une seule opration.
Il existe nanmoins des techniques qui permettent de le faire pour certains langages mais ces techniques dpendent
du langage. Bien que cette technique existe en VBA (ReDim Preserve), elle est trs couteuse en temps d'excution.
Je vous prsente aussi une technique base sur la manipulation de chaines qui fonctionne avec tous les langages
(mais attention cette technique n'est pas optimise pour tous les langages).
On dtermine d'abord un (ou plusieurs) marqueurs de sparation (qui ne sont pas utiliss dans le texte concern)
comme "$$$", "", ""..., puis on utilise une variable de stockage temporaire de type chaine de caractres qui va
contenir les textes concerns les uns aprs les autres spars par le marqueur et on compte le nombre de textes. On
finit alors par crer le tableau (avec la bonne taille qui maintenant est connue) puis on parcourt la chaine, sparateur
aprs sparateur, pour placer les diffrents textes concerns dans le tableau, ce qui est trs rapide.

2-C - Explications

Nom de la macro
Sub DVP_InsererEtOuActualiserUnIndexThematique()

Dclarations des tableaux qui contiennent les variables


Dim
Dim
Dim
Dim

aLstRecettes() As String
aLstTypes() As String
aLstPrix() As String
aLstDiff() As String

Permet d'utiliser des tableaux rinitialisables


Remarque : les indices des tableaux commencent 0
ReDim
ReDim
ReDim
ReDim

aLstRecettes(0 To 0) As String
aLstTypes(0 To 0) As String
aLstPrix(0 To 0) As String
aLstDiff(0 To 0) As String

On rcupre la table des matires (dans la variable aTdM)


Remarque 1 : on considre que
ActiveDocument.Range(Start:=ActiveDocument.TablesOfContents(1).Range.Start, _
End:=ActiveDocument.TablesOfContents(1).Range.End).Select
aTdM = ActiveDocument.TablesOfContents(1).Range.Text

On parcourt la table des matires paragraphe par paragraphe


A chaque paragraphe, on incrment le nombre de recettes et on place le titre de la recette suivi du numro de
page dans une chaine de caractres en les sparant par les marqueurs "$" et ""

-5Ce document est issu de http://www.developpez.com et reste la proprit exclusive de son auteur : Jean-Franois Jousseaume (Sepia sur www.developpez.com). La copie, modification et/ou
distribution par quelque moyen que ce soit est soumise l'obtention pralable de l'autorisation de l'auteur: Jean-Franois Jousseaume (Sepia sur www.developpez.com).

http://sepia.developpez.com/office/word/indexthematique/

Ajout d'un index thmatique dans Word en VBA par Jean-Franois Jousseaume (Sepia sur www.developpez.com)

aNbRecettes = 0
aTmpRecettes = ""
While InStr(aTdM, vbCr) <> 0
aNbRecettes = aNbRecettes + 1
aTmpRecettes = aTmpRecettes + Left(aTdM, InStr(aTdM, vbTab) - 1) + "$" + Left(Mid(aTdM, _
InStr(aTdM, vbTab) + 1), InStr(Mid(aTdM, InStr(aTdM, vbTab) + 1), vbCr) - 1) + ""
aTdM = Mid(aTdM, InStr(aTdM, vbCr) + 1)
Wend

On redimensionne le tableau des recettes (puisqu'on en connait maintenant le nombre)


On stocke la liste des recettes dans un tableau
ReDim aLstRecettes(0 To aNbRecettes)
For aI = 0 To aNbRecettes - 1
aLstRecettes(aI) = Left(aTmpRecettes, InStr(aTmpRecettes, "") - 1)
aTmpRecettes = Mid(aTmpRecettes, Len(aLstRecettes(aI)) + 2)
Next

On parcourt le tableau des titres de recettes pour les rechercher dans le contenu du document soit sur le style
"Titre 1" ou soit sur une variante de la recette
Selection.find.ClearFormatting
Selection.find.Replacement.ClearFormatting
For aI = 0 To aNbRecettes - 1
Selection.HomeKey Unit:=wdStory
'// On regarde si la recette est une recette principale
Selection.find.Style = "Titre 1"
With Selection.find
.Text = Left(aLstRecettes(aI), InStr(aLstRecettes(aI), "$") - 1) + "^p"
.Forward = True
.Wrap = wdFindContinue
.Format = True
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
End With
Selection.find.Execute
...
Next

Lorsqu'on a retrouv la recette, on slectionne le tableau qui suit (pour une recette principale) ou le tableau
qui prcde (pour une variante)
If Selection.find.Found Then
Selection.Next(Unit:=wdTable, Count:=1).Select
Else
Selection.find.Style = "Titre 1 - Variante"
Selection.find.Execute
If Selection.find.Found Then
Selection.Previous(Unit:=wdTable, Count:=1).Select
End If
End If

On vrifie que la slection est bien dans un tableau


Cette vrification n'est pas indispensable (puisqu'on vient de slectionner un tableau) mais elle permet de
pointer du doigt que pour des langages interprts
il faut vrifier les conditions supposes (ici le fait d'tre dans un tableau)

-6Ce document est issu de http://www.developpez.com et reste la proprit exclusive de son auteur : Jean-Franois Jousseaume (Sepia sur www.developpez.com). La copie, modification et/ou
distribution par quelque moyen que ce soit est soumise l'obtention pralable de l'autorisation de l'auteur: Jean-Franois Jousseaume (Sepia sur www.developpez.com).

http://sepia.developpez.com/office/word/indexthematique/

Ajout d'un index thmatique dans Word en VBA par Jean-Franois Jousseaume (Sepia sur www.developpez.com)

If Selection.Information(wdWithInTable) Then
...
End If

On rcupre le contenu du champ de formulaire (type de plat : entre, plat principal...) pour rcuprer tous les
types de plats pour crer des catgories
Remarque : on considre que le champ qui nous intresse est le 1er
On vrifie si la catgorie trouve existe, si elle existe, on ajoute la recette la suite de celle de la mme
catgorie (ReDim Preserve), sinon on cre une nouvelle catgorie avec cette recette
aPasTrouve = True
aJ = LBound(aLstTypes)
While (aJ < UBound(aLstTypes)) And (aPasTrouve)
If (Left(aLstTypes(aJ), InStr(aLstTypes(aJ), "$") - 1) = Selection.FormFields(1).result) Then
aPasTrouve = False
Else
aJ = aJ + 1
End If
Wend
If aPasTrouve Then
aLstTypes(aJ) = Selection.FormFields(1).result + "$"
ReDim Preserve aLstTypes(0 To (aJ + 1))
End If
aLstTypes(aJ) = aLstTypes(aJ) + aLstRecettes(aI) + ""

On supprime le contenu de la table prcdente si elle existe


Pour cela, on se dplace au signet de repre de la table d'index (signet "TitreTableDIndexParCategorie") et
on slectionne jusqu' la prochaine section
Selection.GoTo What:=wdGoToBookmark, Name:="TitreTableDIndexParCategorie"
Selection.Move Unit:=wdCharacter, Count:=2
Selection.MoveEnd Unit:=wdSection, Count:=1
Selection.MoveLeft Unit:=wdCharacter, Count:=3, Extend:=wdExtend

Pour chaque catgorie, on crit le contenu (donc la liste des recettes de cette catgorie) et on le passe en
style "Catgorie de plats"
For aI = LBound(aLstTypes) To UBound(aLstTypes) - 1
With Selection
.TypeText Left(aLstTypes(aI), InStr(aLstTypes(aI), "$") - 1)
.TypeParagraph
.MoveUp Unit:=wdParagraph, Count:=1, Extend:=wdExtend
End With
Selection.Style = ActiveDocument.Styles("Catgorie de plats")
Selection.MoveRight Unit:=wdCharacter, Count:=1
...
Next

On remplace les marqueurs de titres de recettes (ici "$") par des tabulations
With Selection
.TypeText Mid(aLstTypes(aI), InStr(aLstTypes(aI), "$") + 1)
.TypeParagraph
.MoveUp Unit:=wdParagraph, Count:=1, Extend:=wdExtend
End With
Selection.find.ClearFormatting
Selection.find.Replacement.ClearFormatting
With Selection.find
.Text = "$"

-7Ce document est issu de http://www.developpez.com et reste la proprit exclusive de son auteur : Jean-Franois Jousseaume (Sepia sur www.developpez.com). La copie, modification et/ou
distribution par quelque moyen que ce soit est soumise l'obtention pralable de l'autorisation de l'auteur: Jean-Franois Jousseaume (Sepia sur www.developpez.com).

http://sepia.developpez.com/office/word/indexthematique/

Ajout d'un index thmatique dans Word en VBA par Jean-Franois Jousseaume (Sepia sur www.developpez.com)

.Replacement.Text = "^t"
.Forward = True
.Wrap = wdFindStop
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
End With
Selection.find.Execute Replace:=wdReplaceAll

On remplace les marqueurs de pages de chaque recette (ici "") par des sauts de paragraphe
With Selection.find
.Text = ""
.Replacement.Text = "^p"
.Forward = True
.Wrap = wdFindStop
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
End With
Selection.find.Execute Replace:=wdReplaceAll

On remplace les marqueurs de pages de chaque recette (ici "") par des sauts de paragraphe
With Selection.find
.Text = ""
.Replacement.Text = "^p"
.Forward = True
.Wrap = wdFindStop
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
End With
Selection.find.Execute Replace:=wdReplaceAll

On positionne la tabulation droite 18 cm avec des points de suite (comme pour une table des matires)
Selection.ParagraphFormat.TabStops.Add Position:=CentimetersToPoints(18), _
Alignment:=wdAlignTabRight, Leader:=wdTabLeaderDots

On dplace le point d'insertion pour ajouter la nouvelle catgorie aprs celle que l'on vient de traiter
Selection.MoveRight Unit:=wdCharacter, Count:=1

2-D - Code complet de la macro


Sub DVP_InsererEtOuActualiserUnIndexThematique()
Dim aLstRecettes() As String
Dim aLstTypes() As String
Dim aLstPrix() As String
-8Ce document est issu de http://www.developpez.com et reste la proprit exclusive de son auteur : Jean-Franois Jousseaume (Sepia sur www.developpez.com). La copie, modification et/ou
distribution par quelque moyen que ce soit est soumise l'obtention pralable de l'autorisation de l'auteur: Jean-Franois Jousseaume (Sepia sur www.developpez.com).

http://sepia.developpez.com/office/word/indexthematique/

Ajout d'un index thmatique dans Word en VBA par Jean-Franois Jousseaume (Sepia sur www.developpez.com)

Dim aLstDiff() As String


ReDim
ReDim
ReDim
ReDim

aLstRecettes(0 To 0) As String
aLstTypes(0 To 0) As String
aLstPrix(0 To 0) As String
aLstDiff(0 To 0) As String

'// On recupre la TdM


'// Attention, on considre que :
'//
1) La TdM qui nous interresse est la 1ere
'//
2) La TdM est jour
'// La mise jour de la table des matires qu'avec le style "Titre 1"
'//(pour ne pas avoir grer les variantes) ne fonctionne pas
'//
(ils restent toujours pris en compte) ==> traitement manuel
ActiveDocument.Range(Start:=ActiveDocument.TablesOfContents(1).Range.Start, _
End:=ActiveDocument.TablesOfContents(1).Range.End).Select
aTdM = ActiveDocument.TablesOfContents(1).Range.Text
'// On stocke la TdM sous forme d'un tableau
aNbRecettes = 0
aTmpRecettes = ""
While InStr(aTdM, vbCr) <> 0
aNbRecettes = aNbRecettes + 1
aTmpRecettes = aTmpRecettes + Left(aTdM, InStr(aTdM, vbTab) - 1) + "$" + Left(Mid(aTdM, _
InStr(aTdM, vbTab) + 1), InStr(Mid(aTdM, InStr(aTdM, vbTab) + 1), vbCr) - 1) + ""
aTdM = Mid(aTdM, InStr(aTdM, vbCr) + 1)
Wend
ReDim aLstRecettes(0 To aNbRecettes)
For aI = 0 To aNbRecettes - 1
aLstRecettes(aI) = Left(aTmpRecettes, InStr(aTmpRecettes, "") - 1)
aTmpRecettes = Mid(aTmpRecettes, Len(aLstRecettes(aI)) + 2)
Next
'// On parcourt la liste des recettes pour retrouver les catgories
Selection.find.ClearFormatting
Selection.find.Replacement.ClearFormatting
For aI = 0 To aNbRecettes - 1
Selection.HomeKey Unit:=wdStory
'// On regarde si la recette est une recette principale
Selection.find.Style = "Titre 1"
With Selection.find
.Text = Left(aLstRecettes(aI), InStr(aLstRecettes(aI), "$") - 1) + "^p"
.Forward = True
.Wrap = wdFindContinue
.Format = True
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
End With
Selection.find.Execute
If Selection.find.Found Then
Selection.Next(Unit:=wdTable, Count:=1).Select
Else '// On regarde si la recette est une variante
Selection.find.Style = "Titre 1 - Variante"
Selection.find.Execute
If Selection.find.Found Then
Selection.Previous(Unit:=wdTable, Count:=1).Select
End If
End If
If Selection.Information(wdWithInTable) Then
'// Attention, on considre que le champ de formulaire (type de plat : entre, plat principal...)
'// qui nous interresse est le 1er
'// ==> On va rcuprer tous les types de plats pour crer des catgories
aPasTrouve = True
aJ = LBound(aLstTypes)
While (aJ < UBound(aLstTypes)) And (aPasTrouve)
If (Left(aLstTypes(aJ), InStr(aLstTypes(aJ), "$") - 1) = Selection.FormFields(1).result) Then
aPasTrouve = False
-9Ce document est issu de http://www.developpez.com et reste la proprit exclusive de son auteur : Jean-Franois Jousseaume (Sepia sur www.developpez.com). La copie, modification et/ou
distribution par quelque moyen que ce soit est soumise l'obtention pralable de l'autorisation de l'auteur: Jean-Franois Jousseaume (Sepia sur www.developpez.com).

http://sepia.developpez.com/office/word/indexthematique/

Ajout d'un index thmatique dans Word en VBA par Jean-Franois Jousseaume (Sepia sur www.developpez.com)

Else

aJ = aJ + 1
End If
Wend
If aPasTrouve Then
aLstTypes(aJ) = Selection.FormFields(1).result + "$"
ReDim Preserve aLstTypes(0 To (aJ + 1))
End If
aLstTypes(aJ) = aLstTypes(aJ) + aLstRecettes(aI) + ""
End If
Next
'// On supprime le contenu de la table prcdente si elle existe
Selection.GoTo What:=wdGoToBookmark, Name:="TitreTableDIndexParCategorie"
Selection.Move Unit:=wdCharacter, Count:=2
Selection.MoveEnd Unit:=wdSection, Count:=1
Selection.MoveLeft Unit:=wdCharacter, Count:=3, Extend:=wdExtend
For aI = LBound(aLstTypes) To UBound(aLstTypes) - 1
With Selection
.TypeText Left(aLstTypes(aI), InStr(aLstTypes(aI), "$") - 1)
.TypeParagraph
.MoveUp Unit:=wdParagraph, Count:=1, Extend:=wdExtend
End With
Selection.Style = ActiveDocument.Styles("Catgorie de plats")
Selection.MoveRight Unit:=wdCharacter, Count:=1
With Selection
.TypeText Mid(aLstTypes(aI), InStr(aLstTypes(aI), "$") + 1)
.TypeParagraph
.MoveUp Unit:=wdParagraph, Count:=1, Extend:=wdExtend
End With
Selection.find.ClearFormatting
Selection.find.Replacement.ClearFormatting
With Selection.find
.Text = "$"
.Replacement.Text = "^t"
.Forward = True
.Wrap = wdFindStop
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
End With
Selection.find.Execute Replace:=wdReplaceAll
With Selection.find
.Text = ""
.Replacement.Text = "^p"
.Forward = True
.Wrap = wdFindStop
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
End With
Selection.find.Execute Replace:=wdReplaceAll
Selection.ParagraphFormat.TabStops.Add Position:=CentimetersToPoints(18), _
Alignment:=wdAlignTabRight, Leader:=wdTabLeaderDots
Selection.MoveRight Unit:=wdCharacter, Count:=1
Next
End Sub

- 10 Ce document est issu de http://www.developpez.com et reste la proprit exclusive de son auteur : Jean-Franois Jousseaume (Sepia sur www.developpez.com). La copie, modification et/ou
distribution par quelque moyen que ce soit est soumise l'obtention pralable de l'autorisation de l'auteur: Jean-Franois Jousseaume (Sepia sur www.developpez.com).

http://sepia.developpez.com/office/word/indexthematique/

Ajout d'un index thmatique dans Word en VBA par Jean-Franois Jousseaume (Sepia sur www.developpez.com)

Pour les DVPnautes, il ne vous reste plus qu' complter ce livre avec vos propres recettes ou celles de vos amis
et moi vous souhaiter "Bon apptit".

2-E - Le fichier exemple


Vous pouvez tlcharger le fichier exemple ici

3 - Remerciements
Je tiens remercier toutes les personnes qui m'ont aid et conseill de prs ou de loin la rdaction de cet article, et
plus particulirement Olivier Lebeau (Heureux-oli sur DVP) et Lou Pitchoun pour leur aide sans cet article n'aurait
jamais vu le jour.

- 11 Ce document est issu de http://www.developpez.com et reste la proprit exclusive de son auteur : Jean-Franois Jousseaume (Sepia sur www.developpez.com). La copie, modification et/ou
distribution par quelque moyen que ce soit est soumise l'obtention pralable de l'autorisation de l'auteur: Jean-Franois Jousseaume (Sepia sur www.developpez.com).

http://sepia.developpez.com/office/word/indexthematique/