excel-vba
Häufige Fehler
Suche…
Qualifizierende Referenzen
Wenn Sie sich auf ein worksheet
, einen range
oder einzelne cells
beziehen, ist es wichtig, die Referenz vollständig zu qualifizieren.
Zum Beispiel:
ThisWorkbook.Worksheets("Sheet1").Range(Cells(1, 2), Cells(2, 3)).Copy
Ist nicht vollständig qualifiziert: Den Cells
sind keine Arbeitsmappe und kein Arbeitsblatt zugeordnet. Ohne explizite Referenz verweist Cells standardmäßig auf das ActiveSheet
. Daher Sheet1
dieser Code fehl (falsche Ergebnisse), wenn ein anderes Arbeitsblatt als Sheet1
das aktuelle ActiveSheet
.
Die einfachste Möglichkeit, dies zu korrigieren, besteht darin, eine With
Anweisung wie folgt zu verwenden:
With ThisWorkbook.Worksheets("Sheet1")
.Range(.Cells(1, 2), .Cells(2, 3)).Copy
End With
Alternativ können Sie eine Arbeitsblattvariable verwenden. (Diese Methode wird höchstwahrscheinlich bevorzugt, wenn Ihr Code auf mehrere Arbeitsblätter verweisen muss, z. B. das Kopieren von Daten von einem Arbeitsblatt auf ein anderes.)
Dim ws1 As Worksheet
Set ws1 = ThisWorkbook.Worksheets("Sheet1")
ws1.Range(ws1.Cells(1, 2), ws1.Cells(2, 3)).Copy
Ein weiteres häufiges Problem besteht darin, auf die Worksheets-Auflistung zu verweisen, ohne die Arbeitsmappe zu qualifizieren. Zum Beispiel:
Worksheets("Sheet1").Copy
Das Arbeitsblatt Sheet1
ist nicht vollständig qualifiziert und es fehlt eine Arbeitsmappe. Dies kann fehlschlagen, wenn auf mehrere Arbeitsmappen im Code verwiesen wird. Verwenden Sie stattdessen eine der folgenden Möglichkeiten:
ThisWorkbook.Worksheets("Sheet1") '<--ThisWorkbook refers to the workbook containing
'the running VBA code
Workbooks("Book1").Worksheets("Sheet1") '<--Where Book1 is the workbook containing Sheet1
Vermeiden Sie jedoch Folgendes:
ActiveWorkbook.Worksheets("Sheet1") '<--Valid, but if another workbook is activated
'the reference will be changed
Ähnliches gilt für range
Objekte, wenn nicht ausdrücklich qualifiziert, der range
wird auf das aktuell aktive Blatt verweisen:
Range("a1")
Ist das gleiche wie:
ActiveSheet.Range("a1")
Zeilen oder Spalten in einer Schleife löschen
Wenn Sie Zeilen (oder Spalten) in einer Schleife löschen möchten, sollten Sie die Schleife immer am Ende des Bereichs beginnen und in jedem Schritt zurückgehen. Bei Verwendung des Codes:
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
Sie werden einige Reihen vermissen. Wenn der Code beispielsweise Zeile 3 löscht, wird Zeile 4 zu Zeile 3. Die Variable i
ändert sich jedoch zu 4. In diesem Fall wird der Code eine Zeile übersehen und eine andere Zeile überprüfen, die zuvor nicht in Reichweite war.
Der richtige Code wäre
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
und ThisWorkbook
werden von neuen VBA-Benutzern manchmal austauschbar verwendet, ohne zu ThisWorkbook
, worauf sich jedes Objekt bezieht. Beide Objekte gehören zum Anwendungsobjekt
Das ActiveWorkbook
Objekt verweist auf die Arbeitsmappe, die sich zum Zeitpunkt der Ausführung derzeit in der obersten Ansicht des Excel-Anwendungsobjekts befindet. (zB die Arbeitsmappe, mit der Sie an dem Punkt sehen und interagieren können, an dem auf dieses Objekt verwiesen wird)
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
Das ThisWorkbook
Objekt verweist auf die Arbeitsmappe, zu der der Code zum Zeitpunkt der Ausführung gehört.
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
Schnittstelle für ein Dokument vs. mehrere Dokumentschnittstellen
Beachten Sie, dass Microsoft Excel 2013 (und höher) Single Document Interface (SDI) und Excel 2010 (und darunter) Multiple Document Interfaces (MDI) verwenden.
Dies impliziert, dass für Excel 2013 (SDI) jede Arbeitsmappe in einer einzelnen Instanz von Excel eine eigene Menübandoberfläche enthält:
Im Gegensatz dazu wurde für Excel 2010 für jede Arbeitsmappe in einer einzelnen Instanz von Excel eine gemeinsame Ribbon-Benutzeroberfläche (MDI) verwendet:
Dies wirft einige wichtige Probleme auf, wenn Sie einen VBA-Code (2010 <-> 2013) migrieren möchten, der mit der Multifunktionsleiste interagiert.
Es muss eine Prozedur erstellt werden, um die Ribbon-UI-Steuerelemente in allen Arbeitsmappen für Excel 2013 und höher im gleichen Status zu aktualisieren.
Beachten Sie, dass :
- Alle Fenstermethoden, Ereignisse und Eigenschaften auf Excel-Anwendungsebene bleiben davon unberührt. (
Application.ActiveWindow
,Application.Windows
...) - In Excel 2013 und höher (SDI) werden jetzt alle Methoden, Ereignisse und Eigenschaften der Arbeitsmappen auf Fenstern der obersten Ebene ausgeführt. Das Handle dieses obersten Fensters kann mit
Application.Hwnd
abgerufen werden
Weitere Informationen finden Sie in der Quelle dieses Beispiels: MSDN .
Dies verursacht auch einige Probleme mit modelllosen Benutzerformularen. Hier finden Sie eine Lösung.