excel-vba
Veelgemaakte fouten
Zoeken…
In aanmerking komende referenties
Wanneer u verwijst naar een worksheet
, een range
of afzonderlijke cells
, is het belangrijk om de referentie volledig te kwalificeren.
Bijvoorbeeld:
ThisWorkbook.Worksheets("Sheet1").Range(Cells(1, 2), Cells(2, 3)).Copy
Is niet volledig gekwalificeerd: aan de Cells
is geen werkmap en werkblad gekoppeld. Zonder een expliciete verwijzing verwijst cellen standaard naar de ActiveSheet
. Dus deze code zal mislukken (produceren onjuiste resultaten) als een ander werkblad dan Sheet1
het huidige ActiveSheet
.
De eenvoudigste manier om dit te corrigeren is om de With
instructie als volgt te gebruiken:
With ThisWorkbook.Worksheets("Sheet1")
.Range(.Cells(1, 2), .Cells(2, 3)).Copy
End With
U kunt ook een werkbladvariabele gebruiken. (Dit is waarschijnlijk de voorkeursmethode als uw code naar meerdere werkbladen moet verwijzen, zoals het kopiëren van gegevens van het ene naar het andere blad.)
Dim ws1 As Worksheet
Set ws1 = ThisWorkbook.Worksheets("Sheet1")
ws1.Range(ws1.Cells(1, 2), ws1.Cells(2, 3)).Copy
Een ander veel voorkomend probleem is het verwijzen naar de verzameling werkbladen zonder de werkmap te kwalificeren. Bijvoorbeeld:
Worksheets("Sheet1").Copy
Het werkblad Sheet1
is niet volledig gekwalificeerd en heeft geen werkmap. Dit kan mislukken als naar meerdere werkmappen wordt verwezen in de code. Gebruik in plaats daarvan een van de volgende:
ThisWorkbook.Worksheets("Sheet1") '<--ThisWorkbook refers to the workbook containing
'the running VBA code
Workbooks("Book1").Worksheets("Sheet1") '<--Where Book1 is the workbook containing Sheet1
Vermijd echter het volgende:
ActiveWorkbook.Worksheets("Sheet1") '<--Valid, but if another workbook is activated
'the reference will be changed
Hetzelfde geldt voor range
objecten, zo niet expliciet gekwalificeerd, het range
zal verwijzen naar de op dat moment actieve blad:
Range("a1")
Is hetzelfde als:
ActiveSheet.Range("a1")
Rijen of kolommen in een lus verwijderen
Als u rijen (of kolommen) in een lus wilt verwijderen, moet u altijd vanaf het einde van het bereik beginnen en in elke stap teruggaan. In geval van gebruik van de 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
U mist enkele rijen. Als de code bijvoorbeeld rij 3 verwijdert, wordt rij 4 rij 3. Echter, variabele i
verandert in 4. Dus in dit geval zal de code een rij missen en een andere controleren, die eerder niet binnen bereik was.
De juiste code zou zijn
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 versus ThisWorkbook
ActiveWorkbook
en ThisWorkbook
soms door elkaar gebruikt door nieuwe gebruikers van VBA zonder volledig te begrijpen waar elk object betrekking op heeft, dit kan ongewenst gedrag tijdens de uitvoering veroorzaken. Beide objecten behoren tot het toepassingsobject
Het ActiveWorkbook
object verwijst naar de werkmap die op het moment van uitvoering momenteel in de bovenste weergave van het Excel-toepassingsobject staat. (bijv. de werkmap die u kunt zien en waarmee u kunt communiceren op het moment waarop naar dit object wordt verwezen)
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
Het object ThisWorkbook
verwijst naar de werkmap waartoe de code behoort op het moment dat deze wordt uitgevoerd.
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 voor één document versus meerdere documentinterfaces
Houd er rekening mee dat Microsoft Excel 2013 (en hoger) Single Document Interface (SDI) gebruikt en dat Excel 2010 (en lager) Multiple Document Interfaces (MDI) gebruikt.
Dit betekent dat voor Excel 2013 (SDI) elke werkmap in een enkel exemplaar van Excel zijn eigen lint-UI bevat:
Omgekeerd voor Excel 2010 gebruikte elke werkmap in één exemplaar van Excel een gemeenschappelijke lint-UI (MDI):
Dit roept een aantal belangrijke problemen op als u een VBA-code (2010 <-> 2013) wilt migreren die met het lint samenwerkt.
Er moet een procedure worden gemaakt om lint-UI-besturingselementen in alle werkmappen voor Excel 2013 en hoger in dezelfde status bij te werken.
Let daar op :
- Alle venstermethoden, gebeurtenissen en eigenschappen op Excel-toepassingsniveau blijven onaangetast. (
Application.ActiveWindow
,Application.Windows
...) - In Excel 2013 en hoger (SDI) werken alle venstermethoden, gebeurtenissen en eigenschappen op werkmapniveau nu op het bovenste niveau. Het is mogelijk om de toepassing van dit venster op het hoogste niveau op te halen met
Application.Hwnd
Zie de bron van dit voorbeeld voor meer informatie: MSDN .
Dit veroorzaakt ook enige problemen met modelloze gebruikersformulieren. Zie hier voor een oplossing.