excel-vba
Vanliga misstag
Sök…
Kvalificerade referenser
När du hänvisar till ett worksheet
, ett range
eller enskilda cells
är det viktigt att referensen är fullständigt kvalificerad.
Till exempel:
ThisWorkbook.Worksheets("Sheet1").Range(Cells(1, 2), Cells(2, 3)).Copy
Är inte helt kvalificerad: Cells
referenserna har inte en arbetsbok och kalkylblad associerade med dem. Utan en uttrycklig referens hänvisar Cells till ActiveSheet
standard. Så denna kod kommer att misslyckas (ger felaktiga resultat) om ett annat kalkylblad än Sheet1
är det aktuella ActiveSheet
.
Det enklaste sättet att korrigera detta är att använda ett With
uttalande enligt följande:
With ThisWorkbook.Worksheets("Sheet1")
.Range(.Cells(1, 2), .Cells(2, 3)).Copy
End With
Alternativt kan du använda en kalkylvariabelvariabel. (Det här är troligtvis en föredragen metod om din kod behöver referera till flera kalkylblad, till exempel att kopiera data från ett ark till ett annat.)
Dim ws1 As Worksheet
Set ws1 = ThisWorkbook.Worksheets("Sheet1")
ws1.Range(ws1.Cells(1, 2), ws1.Cells(2, 3)).Copy
Ett annat vanligt problem är att referera till kalkylarksamlingen utan att kvalificera arbetsboken. Till exempel:
Worksheets("Sheet1").Copy
Sheet1
är inte fullt kvalificerat och saknar en arbetsbok. Detta kan misslyckas om flera arbetsböcker hänvisas till i koden. Använd istället något av följande:
ThisWorkbook.Worksheets("Sheet1") '<--ThisWorkbook refers to the workbook containing
'the running VBA code
Workbooks("Book1").Worksheets("Sheet1") '<--Where Book1 is the workbook containing Sheet1
Undvik dock att använda följande:
ActiveWorkbook.Worksheets("Sheet1") '<--Valid, but if another workbook is activated
'the reference will be changed
På samma sätt för range
, om inte uttryckligen kvalificerade, hänvisar range
till det aktuella aktiva arket:
Range("a1")
Är det samma som:
ActiveSheet.Range("a1")
Radera rader eller kolumner i en slinga
Om du vill ta bort rader (eller kolumner) i en slinga bör du alltid slinga från början av slutet och flytta tillbaka i varje steg. Vid användning av koden:
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
Du kommer att sakna några rader. Till exempel, om koden raderar rad 3, sedan rad 4 blir rad 3. Men variabel i
kommer att ändras till 4. Så, i detta fall koden kommer att missa en rad och kontrollera en annan, som inte var inom räckhåll tidigare.
Rätt kod skulle vara
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
och ThisWorkbook
ibland utbytbart av nya användare av VBA utan att helt förstå vilket objekt förhåller sig till, detta kan orsaka oönskat beteende vid körning. Båda dessa objekt tillhör applikationsobjektet
ActiveWorkbook
objektet hänvisar till den arbetsbok som för närvarande är högst upp i Excel-applikationsobjektet vid körningstillfället. (t.ex. arbetsboken som du kan se och interagera med vid den punkt då det hänvisas till detta objekt)
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
ThisWorkbook
objektet hänvisar till den arbetsbok som koden tillhör vid den tidpunkt då den körs.
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
Enstaka dokumentgränssnitt kontra flera dokumentgränssnitt
Var medveten om att Microsoft Excel 2013 (och senare) använder Single Document Interface (SDI) och att Excel 2010 (och nedan) använder Multiple Document Interfaces (MDI).
Detta innebär att för Excel 2013 (SDI) innehåller varje arbetsbok i en enda instans av Excel sitt eget band UI:
Omvänt för Excel 2010 använde varje arbetsbok i en enda instans av Excel ett vanligt band UI (MDI):
Detta väcker några viktiga frågor om du vill migrera en VBA-kod (2010 <-> 2013) som interagerar med bandet.
En procedur måste skapas för att uppdatera UI-kontrollerna för band i samma tillstånd i alla arbetsböcker för Excel 2013 och Higher.
Anteckna det :
- Alla Excel-applikationsnivåfönster, händelser och egenskaper förblir opåverkade. (
Application.ActiveWindow
,Application.Windows
...) - I Excel 2013 och högre (SDI) fungerar nu alla fönstermetoder, händelser och egenskaper på arbetsbokenivån i det övre nivåfönstret. Det är möjligt att hämta handtaget i detta toppnivå med
Application.Hwnd
För mer information, se källan till detta exempel: MSDN .
Detta orsakar också problem med användarformerna för modelllösa. Se Här för en lösning.