FAQ VBA
FAQ VBAConsultez toutes les FAQ
Nombre d'auteurs : 10, nombre de questions : 133, dernière mise à jour : 15 juin 2021
- Comment ajouter un classeur contenant juste une feuille ?
- Comment ouvrir un classeur ?
- Comment travailler sur deux classeurs ?
- Comment fermer un classeur sans enregistrer les changements ?
- Je ne comprends pas la protection du classeur !
- Comment dupliquer une plage sur plusieurs feuilles du classeur ?
- Quelle différence entre ActiveWorkbook et ThisWorkbook ?
- Comment écrit-on une fonction de feuille de calcul ?
- Peut-on supprimer les liaisons d'un classeur ?
- Comment empêcher la fermeture de mon classeur ?
Il y a deux méthodes. On peut restreindre le nombre de feuilles de calcul créées dans un nouveau classeur
Application.SheetsInNewWorkbook
=
1
Application.Workbooks.Add
Seulement cela est un paramétrage de l'application et il faudrait restaurer l'ancienne valeur. On peut aussi créer un classeur contenant une feuille de type spécifique
Application.Workbooks.Add
xlWBATWorksheet
contient une feuille de calcul
Application.Workbooks.Add
xlWBATChart
Contient une feuille graphique
On utilise la méthode Open de la collection WorkBooks Elle accepte plusieurs paramètres dont quelques-uns sont utiles à connaître, FileName est le seul paramètre obligatoire. Il doit contenir le chemin complet
Application.Workbooks.Open
"d:\tuto.xls"
On peut aussi passer par la méthode GetOpenFilename pour laisser l'utilisateur sélectionner le fichier
Application.Workbooks.Open
Application.GetOpenFilename
(
)
Les paramètres intéressants supplémentaires sont : UpdateLinks Une référence externe appartient à un autre classeur, une référence distante appartient à un autre programme. ReadOnly Booléen qui définit si le classeur doit être ouvert en lecture seule Password Représente le mot de passe pour un classeur à ouverture protégée
- 0--> Ne met à jour aucune référence
- 1--> Met à jour des références externes mais pas des références distantes
- 2--> Met à jour des références distantes mais pas des références externes
- 3--> Met à jour des références distantes et des références externes
Dans ce cas on utilises des variables
Dim
objWorkbookSource As
Workbook, objWorkbookCible As
Workbook
set
objWorkbookSource =
Application.Workbooks.Open
(
Application.GetOpenFilename
)
set
objWorkbookCible =
Application.Workbooks.Add
Il ne reste plus qu'à basculer entre les deux variables
Il suffit de faire
ActiveWorkbook.Close
False
La méthode Close permet de gérer un grand nombre de cas. Sa syntaxe générale est :
Close
(
SaveChanges, FileName, RouteWorkbook)
Si SaveChanges est vrai et que le classeur n'a pas encore été enregistré, il utilisera la valeur de filename. Si celle-ci n'est pas précisée, il y aura appel de la boîte de dialogue SaveAs.
Dans Excel, la protection d'un objet ne joue que sur les descendants directs. Je m'explique : la protection d'un classeur ne protège que ses fenêtres et sa structure de feuille. Si je fais :
ActiveWorkbook.Protect
Password:=
"monpasse"
, Structure:=
True
, Windows:=
False
Je ne protège que la structure. Cela veut dire qu'il n'est pas possible d'ajouter, de supprimer ou de déplacer des feuilles. En aucun cas cela ne protège les cellules. Pour cela il faut protéger la ou les feuilles.
On utilise la méthode FillAcrossSheet de l'objet WorkBook
ThisWorkbook.Worksheets.FillAcrossSheets
Range
(
"A1:C10"
), xlFillWithAll
Notez que le deuxième paramètre permet de préciser si on veut dupliquer le contenu, le format ou les deux.
ThisWorkbook représente le classeur qui contient le code faisant appel à thisWorkbook. Active Workbook représente le classeur actif de l'application. De manière générale, il vaut mieux éviter les objets actifs et privilégier des variables, car la programmation des objets actifs est assez piègeuse : ceux-ci tendent à ne plus l'être (actif) quand on en a besoin. Prenons un exemple.
Set
objSheet =
ThisWorkbook.Sheets
(
"recup"
)
Application.Workbooks.Open
"d:\user\tuto1.xls"
ActiveWorkbook.OpenLinks
Name:=
ActiveWorkbook.LinkSources
(
xlExcelLinks)
Après l'appel de OpenLinks plus de possibilité de savoir aisément quel classeur est désigné par ActiveWorkbooks
Il s'agit d'une fonction normale.Par exemple
Function
InvChaine
(
Cellule As
Range) As
Variant
Dim
MaChaine As
String
, cmpt As
Long
If
Len
(
Cellule.Value
) =
0
Then
InvChaine =
CVErr
(
xlErrValue)
Else
MaChaine =
CStr
(
Cellule.Value
)
For
cmpt =
Len
(
MaChaine) To
1
Step
-
1
InvChaine =
InvChaine &
Mid
(
MaChaine, cmpt, 1
)
Next
cmpt
End
If
End
Function
Si dans votre feuille vous écrivez la formule =invchaine(E2) La cellule contiendra la chaine retournée ou #VALEUR
Ce n'est pas toujours évident. Pour supprimer les liaisons il y a globalement deux méthodes. Une recherche complète permettant la récupération de ce qui est récupérable
Sub
ChercheLiaison
(
)
Dim
NomFichier As
String
, MonClasseur As
Workbook, Liaisons As
Variant
Dim
compteur As
Long
, comptCar As
Long
, Cible As
Range
Dim
FirstAddress As
String
, PlageLiee As
Range, comptFeuille As
Long
, Reponse As
Integer
Dim
MaFeuille As
Worksheet, MonGraphe As
Chart, MonGraphe1 As
ChartObject, MaSerie As
Series
NomFichier =
Application.GetOpenFilename
Workbooks.Open
NomFichier, False
Set
MonClasseur =
ActiveWorkbook
Liaisons =
MonClasseur.LinkSources
If
IsEmpty
(
Liaisons) Then
Exit
Sub
'parcours les feuilles
For
Each
MaFeuille In
MonClasseur.Worksheets
MaFeuille.Activate
MaFeuille.Cells.Select
For
compteur =
1
To
UBound
(
Liaisons)
For
comptCar =
Len
(
Liaisons
(
compteur)) To
1
Step
-
1
If
Mid
(
Liaisons
(
compteur), comptCar, 1
) =
"\"
Then
Liaisons
(
compteur) =
Mid
(
Liaisons
(
compteur), comptCar +
1
)
Exit
For
End
If
Next
comptCar
Set
Cible =
Selection.Find
(
What:=
Liaisons
(
compteur), After:=
ActiveCell, LookIn:=
xlFormulas, _
LookAt:=
xlPart, SearchOrder:=
xlByRows, SearchDirection:=
xlNext, _
MatchCase:=
False
)
If
Not
Cible Is
Nothing
Then
FirstAddress =
Cible.Address
Do
If
PlageLiee Is
Nothing
Then
Set
PlageLiee =
Cible Else
Set
PlageLiee =
Union
(
PlageLiee, Cible)
Set
Cible =
Selection.FindNext
(
After:=
Cible)
Loop
While
Not
Cible Is
Nothing
And
Cible.Address
<>
FirstAddress
End
If
Next
compteur
If
Not
PlageLiee Is
Nothing
Then
Reponse =
MsgBox
(
"La feuille "
&
MaFeuille.Name
&
" contient "
&
PlageLiee.Cells.Count
&
_
" cellules avec des liaisons"
&
vbCrLf
&
_
"voulez-vous les supprimer ?"
, vbYesNo
+
vbQuestion
, "Liaisons trouvées"
)
If
Reponse =
6
Then
For
Each
Cible In
PlageLiee.Cells
Cible.Formula
=
Cible.Value
Next
End
If
Set
PlageLiee =
Nothing
End
If
For
Each
MonGraphe1 In
MaFeuille.ChartObjects
For
Each
MaSerie In
MonGraphe1.SeriesCollection
For
compteur =
1
To
UBound
(
Liaisons)
If
InStr
(
1
, MaSerie.Formula
, Liaisons
(
compteur), vbTextCompare) >
0
Then
Reponse =
MsgBox
(
"le graphe de la feuille "
&
MonGraphe1.Name
&
_
" contient une série "
&
MaSerie.Name
&
" avec des liaisons"
&
vbCrLf
&
_
"Voulez-vous les supprimer ?"
, vbYesNo
+
vbQuestion
, "Liaisons trouvées"
)
If
Reponse =
6
Then
MaSerie.Delete
Exit
For
End
If
End
If
Next
compteur
Next
Next
Next
For
Each
MonGraphe In
MonClasseur.Charts
For
Each
MaSerie In
MonGraphe.SeriesCollection
For
compteur =
1
To
UBound
(
Liaisons)
If
InStr
(
1
, MaSerie.Formula
, Liaisons
(
compteur), vbTextCompare) >
0
Then
Reponse =
MsgBox
(
"le graphe de la feuille "
&
MonGraphe.Name
&
_
" contient une série "
&
MaSerie.Name
&
" avec des liaisons"
&
vbCrLf
&
_
"voulez-vous les supprimer ?"
, vbYesNo
+
vbQuestion
, "Liaisons trouvées"
)
If
Reponse =
6
Then
MaSerie.Delete
Exit
For
End
If
End
If
Next
compteur
Next
Next
End
Sub
Une méthode beaucoup plus violente qui consiste à modifier les liaisons par le nom du classeur source. Cela va créer des références circulaires qu'il faudra alors supprimer. Les données anciennement liées seront perdues.
Dim
Nom As
String
, objWorkbook As
Workbook, TabLiaison As
Variant
, cmpt As
Long
Dim
objWorksheet As
Worksheet, objRange As
Range
Set
objWorkbook =
Application.Workbooks.Open
(
Application.GetOpenFilename
, UpdateLinks:=
0
)
TabLiaison =
objWorkbook.LinkSources
(
xlExcelLinks)
If
IsEmpty
(
TabLiaison) Then
Exit
Sub
For
cmpt =
LBound
(
TabLiaison) To
UBound
(
TabLiaison)
objWorkbook.ChangeLink
TabLiaison
(
cmpt), objWorkbook.FullName
, xlLinkTypeExcelLinks
Next
cmpt
For
Each
objWorksheet In
objWorkbook.Worksheets
Do
Set
objRange =
objWorksheet.CircularReference
If
Not
objRange Is
Nothing
Then
objRange.Value
=
objRange.Value
Loop
While
Not
objRange Is
Nothing
Dans le module ThisWorkbook on met
Private
Sub
Workbook_BeforeClose
(
Cancel As
Boolean
)
Cancel=
true
End
Sub
Comme à un moment il faudra fermer le classeur on désactivera la gestion des événements
Application.EnableEvents
=
False
ThisWorkbook.Close
True