excel-vba
Erreurs courantes
Recherche…
Références éligibles
En faisant référence à une worksheet
, à une range
ou à des cells
individuelles, il est important de qualifier complètement la référence.
Par exemple:
ThisWorkbook.Worksheets("Sheet1").Range(Cells(1, 2), Cells(2, 3)).Copy
N'est pas entièrement qualifié: les références de Cells
ne sont pas associées à un classeur et à une feuille de calcul. Sans référence explicite, Cells fait référence à ActiveSheet
par défaut. Ce code échouera donc (produira des résultats incorrects) si une feuille de calcul autre que Sheet1
est l'actuelle ActiveSheet
.
La manière la plus simple de corriger cela est d'utiliser une instruction With
comme suit:
With ThisWorkbook.Worksheets("Sheet1")
.Range(.Cells(1, 2), .Cells(2, 3)).Copy
End With
Vous pouvez également utiliser une variable de feuille de calcul. (Cela sera probablement la méthode préférée si votre code doit référencer plusieurs feuilles de calcul, comme la copie de données d'une feuille à une autre.)
Dim ws1 As Worksheet
Set ws1 = ThisWorkbook.Worksheets("Sheet1")
ws1.Range(ws1.Cells(1, 2), ws1.Cells(2, 3)).Copy
Un autre problème fréquent est le référencement de la collection Worksheets sans qualifier le classeur. Par exemple:
Worksheets("Sheet1").Copy
La feuille de calcul Sheet1
n'est pas entièrement qualifiée et ne contient pas de classeur. Cela peut échouer si plusieurs classeurs sont référencés dans le code. Utilisez plutôt l'une des options suivantes:
ThisWorkbook.Worksheets("Sheet1") '<--ThisWorkbook refers to the workbook containing
'the running VBA code
Workbooks("Book1").Worksheets("Sheet1") '<--Where Book1 is the workbook containing Sheet1
Cependant, évitez d'utiliser les éléments suivants:
ActiveWorkbook.Worksheets("Sheet1") '<--Valid, but if another workbook is activated
'the reference will be changed
De même pour les objets de range
, s’ils ne sont pas explicitement qualifiés, la range
se réfère à la feuille actuellement active:
Range("a1")
Est le même que:
ActiveSheet.Range("a1")
Suppression de lignes ou de colonnes dans une boucle
Si vous souhaitez supprimer des lignes (ou des colonnes) dans une boucle, vous devez toujours effectuer une boucle à partir de la fin de la plage et revenir à chaque étape. En cas d'utilisation du code:
Dim i As Long
With Workbooks("Book1").Worksheets("Sheet1")
For i = 1 To 4
If IsEmpty(.Cells(i, 1)) Then .Rows(i).Delete
Next i
End With
Vous allez manquer certaines lignes. Par exemple, si le code supprime la ligne 3, la ligne 4 devient la ligne 3. Cependant, la variable i
passera à 4. Ainsi, dans ce cas, le code manquera une ligne et en vérifiera une autre, qui n'était pas dans la plage précédente.
Le bon code serait
Dim i As Long
With Workbooks("Book1").Worksheets("Sheet1")
For i = 4 To 1 Step -1
If IsEmpty(.Cells(i, 1)) Then .Rows(i).Delete
Next i
End With
ActiveWorkbook vs. ThisWorkbook
ActiveWorkbook
et ThisWorkbook
parfois utilisés indifféremment par les nouveaux utilisateurs de VBA sans comprendre parfaitement à quoi chaque objet se rapporte, cela peut entraîner un comportement indésirable au moment de l'exécution. Ces deux objets appartiennent à l' objet d'application
L'objet ActiveWorkbook
fait référence au classeur qui se trouve actuellement dans la vue la plus haute de l'objet d'application Excel au moment de l'exécution. (Par exemple, le classeur avec lequel vous pouvez voir et interagir au moment où cet objet est référencé)
Sub ActiveWorkbookExample()
'// Let's assume that 'Other Workbook.xlsx' has "Bar" written in A1.
ActiveWorkbook.ActiveSheet.Range("A1").Value = "Foo"
Debug.Print ActiveWorkbook.ActiveSheet.Range("A1").Value '// Prints "Foo"
Workbooks.Open("C:\Users\BloggsJ\Other Workbook.xlsx")
Debug.Print ActiveWorkbook.ActiveSheet.Range("A1").Value '// Prints "Bar"
Workbooks.Add 1
Debug.Print ActiveWorkbook.ActiveSheet.Range("A1").Value '// Prints nothing
End Sub
L'objet ThisWorkbook
fait référence au classeur auquel appartient le code au moment de son exécution.
Sub ThisWorkbookExample()
'// Let's assume to begin that this code is in the same workbook that is currently active
ActiveWorkbook.Sheet1.Range("A1").Value = "Foo"
Workbooks.Add 1
ActiveWorkbook.ActiveSheet.Range("A1").Value = "Bar"
Debug.Print ActiveWorkbook.ActiveSheet.Range("A1").Value '// Prints "Bar"
Debug.Print ThisWorkbook.Sheet1.Range("A1").Value '// Prints "Foo"
End Sub
Interface de document unique et interfaces de documents multiples
Sachez que Microsoft Excel 2013 (et versions ultérieures) utilise l'interface SDI (Single Document Interface) et qu'Excel 2010 (et ci-dessous) utilise plusieurs interfaces de document (MDI).
Cela implique que pour Excel 2013 (SDI), chaque classeur d'une seule instance d'Excel contient sa propre interface utilisateur de ruban:
A l' inverse pour Excel 2010, chaque classeur dans une seule instance d'Excel utilise une interface de ruban commun (MDI):
Cela pose des problèmes importants si vous souhaitez migrer un code VBA (2010 <-> 2013) qui interagit avec le ruban.
Une procédure doit être créée pour mettre à jour les contrôles de l'interface utilisateur du ruban dans le même état sur tous les classeurs pour Excel 2013 et versions ultérieures.
Notez que :
- Toutes les méthodes, événements et propriétés de fenêtre au niveau de l'application Excel restent inchangés. (
Application.ActiveWindow
,Application.Windows
...) - Dans Excel 2013 et versions ultérieures (SDI), toutes les méthodes, tous les événements et toutes les propriétés de la fenêtre au niveau du classeur fonctionnent désormais dans la fenêtre de niveau supérieur. Il est possible de récupérer le descripteur de cette fenêtre de niveau supérieur avec
Application.Hwnd
Pour plus de détails, voir la source de cet exemple: MSDN .
Cela provoque également des problèmes avec les formes utilisateur sans modèle. Voir ici pour une solution.