daniel hofer excel vba referenz - office | · pdf filediese kurz-referenz zu excel vba...
TRANSCRIPT
© 2014 Daniel Hofer Version 3.2 / 14.10.2014 Seite 1 von 74
Daniel Hofer
Excel VBA
Referenz
Seite 2 von 74 Version 3.2 / 14.10.2014 © 2014 Daniel Hofer
© 2014 Daniel Hofer Version 3.2 / 14.10.2014 Seite 3 von 74
Daniel Hofer
Excel VBA Referenz
© Bern, 2014
Seite 4 von 74 Version 3.2 / 14.10.2014 © 2014 Daniel Hofer
© 2014 Daniel Hofer Version 3.2 / 14.10.2014 Seite 5 von 74
Impressum
© 2014 Daniel Hofer
Excel VBA-Referenz
978-3-906284-16-3 (PDF)
978-3-906284-13-2 (Print-Version A5)
978-3-906284-08-8 (Apple iBooks)
Publiziert durch:
Daniel Hofer, Bern, Schweiz
E-Mail: [email protected]
www.officehilfe.ch
Alle Rechte vorbehalten. Die Verwendung der Texte und Bilder, auch auszugsweise,
ist ohne die schriftliche Zustimmung des Autors und Verlags urheberrechtswidrig
und strafbar. Das gilt insbesondere für die Vervielfältigung, Übersetzung, die
Verwendung in Kursunterlagen oder elektronischen Systemen. Der Autor wie auch
Verlag übernehmen keine Haftung für Folgen, die auf unvollständige oder
fehlerhafte Angaben in diesem Buch zurückzuführen sind. Nahezu alle in diesem
Buch behandelten Hard- und Softwarebezeichnungen sind zugleich eingetragene
Warenzeichen.
Seite 6 von 74 Version 3.2 / 14.10.2014 © 2014 Daniel Hofer
Schreibkonventionen
Die einzelnen Themen werden durch blaue Überschriften getrennt.
Code-Beispiele werden grau schattiert dargestellt, zusätzlich erscheinen sie in der
Schriftart „Courier New“.
Hat eine Code-Zeile nicht auf einer Blatt-Zeile Platz, wird die Zeile mit einem _
umgebrochen, genau wie es im VB-Editor auch möglich ist.
Einleitung
Diese Kurz-Referenz zu Excel VBA entstand im Rahmen diverser Excel 2007 VBA-
Kurses bei der Firma Digicomp Academy AG. Diese Referenz wird laufend
überarbeitet. Neu besprochene Themen werden ergänzt. Fehler und
Änderungswünsche melden Sie bitte unter [email protected].
Unterdessen enthält diese Referenz Infos zu sämtlichen gängigen Excel-Versionen.
Passt die Info nur zu einer spezifischen Excel-Version, wird dies im entsprechenden
Kapitel vermerkt.
Letzte Änderungen Version Anpassungen
2.5 Import von verschiedenen Quellen (Textfiles, DBase) Zugriff auf Access-DB’s mittels DAO und ADO
2.6 Anpassungen der Homepages Neues Kapitel „Automation“ hinzugefügt
2.7 Fehlerkorrektur in Import-Kapitel Öffnen von Excel-Dateien im Allgemeinen Öffnen-Dialog inkl. Mehrfachauswahl Komplexer Import von acht Excel-Dateien (Anfügen der Daten untereinander)
2.8 Add-Ins aktualisiert Bild einfügen
2.9 Index am Ende des Dokuments eingefügt, div. Anpassungen, WITH, Textfunktionen, Binärer vs. Textvergleich, MsgBox in 2 Varianten, Zellen auf Gültigkeit prüfen
3.0 Fehlerbereinigungen
3.1 Datums-Funktionen, Formulare
3.2 Fehlerkorrekturen, Makrorekorder, Outlook öffnen und Email versenden
geplant Pivot, relative vs. absolute Aufzeichnung
© 2014 Daniel Hofer Version 3.2 / 14.10.2014 Seite 7 von 74
Inhalt
Impressum ................................................................................................................. 5
Schreibkonventionen ................................................................................................. 6
Einleitung ................................................................................................................... 6
Letzte Änderungen ..................................................................................................... 6
Excel 2007/2010 Special ............................................................................................. 9
Zugriff auf Zellen und Bereiche ................................................................................ 11
Nur einen Teil eines Zellinhaltes (Text) farbig markieren ...................................... 12
Autofilter, Formeln ............................................................................................... 13
Suchen und Finden im Range-Objekt .................................................................... 13
Spezielle Zellen ..................................................................................................... 14
Zelleigenschaften ................................................................................................. 15
Zugriff auf Spalten oder Zeilen ............................................................................. 15
Performance-Vergleich ......................................................................................... 16
Der Makrorekorder .............................................................................................. 18
Tabellenblätter / Dateien ......................................................................................... 22
Excel-Dokumente speichern ................................................................................. 22
Excel-Dateien öffnen ............................................................................................ 23
Öffnen-Dialog anzeigen ........................................................................................ 24
Öffnen-Dialog und darin mehere Dateien auswählen ........................................... 25
Neue Excel-Mappe erstellen ................................................................................. 25
VBA-Grundlagen ....................................................................................................... 26
Variablen .............................................................................................................. 26
Aufzählungen (Enumerationen) ............................................................................ 28
Funktionen ........................................................................................................... 29
Gültigkeitsbereiche ............................................................................................... 30
Arrays ................................................................................................................... 31
WITH .................................................................................................................... 32
MsgBox ................................................................................................................. 33
vb-Konstanten ...................................................................................................... 34
Schleifen ............................................................................................................... 35
Fehler-Behandlung (z.B. InputBox) ....................................................................... 37
Text-Funktionen ................................................................................................... 42
Datums-Funktionen .............................................................................................. 44
Seite 8 von 74 Version 3.2 / 14.10.2014 © 2014 Daniel Hofer
Zellen auf Gültigkeit überprüfen .......................................................................... 45
Formulare in Excel .................................................................................................... 48
Aufruf eines Formulars ......................................................................................... 48
Schliessen des Formulars, Variante 1 ................................................................... 49
Schliessen des Formulars, Variante 2 ................................................................... 49
Parameter-Übergabe mittels globaler Variable .................................................... 49
Textfeld nur zur Eingabe von Zahlen definieren ................................................... 50
Rotes Schliessen-Kreuz ignorieren ........................................................................ 50
Import aus anderen Quellen .................................................................................... 51
Einlesen einer Textdatei ....................................................................................... 51
Excel-Datei öffnen und Daten daraus kopieren .................................................... 52
Komplexe Datenübername aus mehreren Excel-Dateien ..................................... 53
Zugriff auf Access mittels DAO ............................................................................. 54
Einlesen einer dBase-Tabelle über ADO ............................................................... 56
Bild in Excel einfügen ............................................................................................ 57
Diverses ................................................................................................................... 58
Verweise, Early-Binding und Late-Binding ............................................................ 58
Automation (Steuerung anderer Applikationen) .................................................. 59
Tabellenfunktionen .............................................................................................. 61
Zugriff auf das System .......................................................................................... 62
Einstellungen VBA-Editor ...................................................................................... 62
Homepages zu Excel ................................................................................................ 67
Allgemein zu Office und VBA ................................................................................ 67
Excel ..................................................................................................................... 67
Homepages zu Access .......................................................................................... 67
Ribbons .................................................................................................................... 68
Datentypen .............................................................................................................. 72
Index ........................................................................................................................ 73
Excel 2007/2010 Special
© 2014 Daniel Hofer Version 3.2 / 14.10.2014 Seite 9 von 74
Excel 2007/2010 Special
Limitationen, die wichtigsten Änderungen
Spalten 16‘384 256
Zeilen 1‘048‘576 65‘536
Sortierschlüssel 64 3
Farben 4‘294‘967‘296 56
Zellformate 65‘536 Ca. 4‘000
Verschachtelungen in Funktionen 64 7
Zeichen in Formeln 8‘192 1‘024
Bedingungen von bedingten
Formatierungen
Unbeschränkt 3
Argumente von Funktionen 255 30
Elemente von Autofilter-Auswahllisten 10‘000 1‘000 Quelle: www.xlam.ch
Dateiendungen
XLSX: „normale“ Excel-Datei ohne Makros (XML-Format)
XLSM: Datei mit Makro (XML-Format
XLTX: Vorlage ohne Makro (XML-Format
XLTM: Vorlage mit Makros (XML-Format
XLSB: Binäres Dateiformat (z.B. Personal.xlsb)
XLAM: Add-In-Datei (siehe Kapitel „Zugriff auf Funktionen in Add-In Dateien“ auf
Seite 65)
PERSONAL.XLSB, Pfad unter Vista:
C:\Users\[user]\AppData\Roaming\Microsoft\Excel\XLSTART
Objektmodell, was fehlt?
Diverse Bereiche in Excel 2007 können nicht über das Objektmodell angesprochen werden. Dies sind u.a.
das Ribbon (die neuen Buttons)
SmartArt-Grafiken
FileSearch-Objekt (siehe "Scripting Runtime im Kapitel "Diverses")
Schnellzugriffsleiste
Erweiterte Zwischenablage
Excel 2007/2010 Special
Seite 10 von 74 Version 3.2 / 14.10.2014 © 2014 Daniel Hofer
Was fehlt sonst noch?
Smart Tags können nicht mit VBA erstellt werden
ebenfalls Aufgabenbereiche (rechte Spalte) fehlen
Gewisse Abhilfe schafft hier der Einsatz von: Visual Studio Tools for Office (VSTO)
Probleme in Excel 2007
Steuerelemente direkt auf dem Tabellenblatt verursachen häufig
unnachvollziehbare Fehler
Logitech-Maus-Rad funktioniert in der VBA-Umgebung u.U. nicht
Zugriff auf Zellen und Bereiche
© 2014 Daniel Hofer Version 3.2 / 14.10.2014 Seite 11 von 74
Zugriff auf Zellen und Bereiche
Wert 6.3 wird in Zelle A1 geschrieben
Range("A1").Value = 6.3
Farbe des Bereichs „Testbereich“ wird gesetzt
Range("Testbereich").Interior.ColorIndex = 7
Achtung! Der Verweis auf H21 stimmt nur in der Zelle A1. In den anderen wird er jeweils angepasst. Range("A1:B17").FormulaLocal = "=H21"
Leicht andere Syntax
Range("B4", "C10").Clear
Zelle mit der Adresse A20 (Zeile 20, Spalte 1)
Cells(20, 1).Interior.ColorIndex = 9
Bereich A20 bis B21 wird eingefärbt
Range(Cells(20, 1), Cells(21, 2)).Interior.ColorIndex =
9
Range-Aufruf korrekt
Worksheets(„Tabelle1“).Range(„B4“)
Der Wert wird nicht aus der aktuellen Zelle, sondern aus einer darunter
genommen
vAlter = ActiveCell.Offset(1, 0)
Aktueller Bereich um die aktuelle Zelle markieren
ActiveCell.CurrentRegion.Select
Erste Zeile in der „CurrentRegion“
ActiveCell.CurrentRegion.Row
Anzahl Zeilen in der „CurrentRegion“
ActiveCell.CurrentRegion.Rows.Count
Letzte Zeile im Bereich „CurrentRegion“
ActiveCell.CurrentRegion.Rows.Count – 1
Spalte A im Bereich „CurrentRegion“ markieren
vRows = Range("a1").CurrentRegion.Rows.Count
vRange = "A1:A" & vRows
Range(vRange).Select
Zugriff auf Zellen und Bereiche
Seite 12 von 74 Version 3.2 / 14.10.2014 © 2014 Daniel Hofer
Sämtliche Daten markieren
ActiveSheet.UsedRange.Select
Relative Bezüge
Die aktive Zelle ist als Beispiel „I22“. Führt man folgende Codezeile aus, steht dann in dieser Zelle „=H21“
ActiveCell.FormulaR1C1 = "=R[-1]C[-1]"
Alle Zeilen markieren, welche einen Kommentar enthalten
Selection.SpecialCells(xlCellTypeComments).Select
Nur einen Teil eines Zellinhaltes (Text) farbig markieren
Cells(2,2).Characters(Start:=7,
Length:=3).Font.ColorIndex=3
Zugriff auf Zellen und Bereiche
© 2014 Daniel Hofer Version 3.2 / 14.10.2014 Seite 13 von 74
Autofilter, Formeln
Autofilter ein- oder ausschalten
ActiveCell.AutoFilter
Autofilter der Spalte 3
Selection.AutoFilter Field:=3, Criteria1:="<40"
Autofilter, die grössten 2 Werte
Selection.AutoFilter Field:=3,Criteria1:="2", _
Operator:=xlTop10Items
Datum formatieren
vDatum = Format(Now(), "dd. mmmm yyyy")
CHF-Formatierung von Zahlen
Selection.NumberFormat = """CHF ""#,##0.00"
Summenformel in VBA
Dim rngArea As Range
Set rngArea = Range(Cells(1, 1), Cells(5, 1))
Selection.Value = _
Application.WorksheetFunction.Sum(rngArea)
Summenformel in Formula-Eigenschaft der Zelle schreiben
Dim vSummeFormel
vSummeFormel = "=SUM(r" & 1 & "c" & 1 & ":" & "r5c1)"
Selection.Formula = vSummeFormel
Resultat im Sheet:
=SUMME($A$1: $A$5)
Mit VBA einen Bereich summieren
Wollen Sie direkt in VBA die Zellen A1 bis A10 addieren, suchen Sie vergebens
eine VBA-Funktion, welche das erledigt. Hier müssen Sie auf die Excel-Funktion
ausweisen: vSumme = Application.WorksheetFunction.Sum(Range("B15:B18"))
Suchen und Finden im Range-Objekt
Einfachste Variante, um nach dem Text „Datum“ zu suchen in der
aktuellen Markierung
Problem: Wird nichts gefunden, erscheint eine Fehlermeldung
Selection.Find("Datum").Select
Zugriff auf Zellen und Bereiche
Seite 14 von 74 Version 3.2 / 14.10.2014 © 2014 Daniel Hofer
Bessere Suchfunktion
Dim rng As Range
Set rng = Selection.Find("Datum")
If rng Is Nothing Then
MsgBox "Nix gefunden"
Else
rng.Select
End If
Noch besser: Der Text „Datum“ kann nur als Teil in einer Zelle
vorkommen.
Anstelle gleich auf den gefunden Text zu springen (mit .Select) kann dieser
Bereich in eine Variable gelesen und weiterverarbeitet werden
Dim rng As Range
Set rng = Selection.Find("Datum", _
, , xlPart, , , False)
If rng Is Nothing Then
MsgBox "Nix gefunden"
Else
rng.Select
End If
Spezielle Zellen
Max. Anzahl Zeilen
ActiveSheet.Rows.Count
Max. Anzahl Spalten
ActiveSheet.Columns.Count
Sprung zur letzten Zelle, welche entweder in der Spalte oder in der Zeile
einen Inhalt hat
Selection.SpecialCells(xlCellTypeLastCell).Select
Achtung! Diese Funktion ist nicht zuverlässig!
Mögliche Lösungen stehen hier:
http://www.vb-fun.de/cgi-bin/loadframe.pl?ID=vb/tipps/tip0342.shtml
Ergänzung 3.2.2008: Diese Methode funktioniert, wenn das Dokument
vorgängig gespeichert wird, z.B. mit
ActiveWorkbook.Save
Zugriff auf Zellen und Bereiche
© 2014 Daniel Hofer Version 3.2 / 14.10.2014 Seite 15 von 74
Zelleigenschaften
Aktuelle Zelle farbig hinterlegen
ActiveCell.Interior.ColorIndex = 6
Adresse der entsprechenden Zelle erfahren
ActiveCell.Address
ergibt " $A$8".
Sollen die Dollarzeichen entfernt werden, geben wir ein:
Debug.Print ActiveCell.Address(False, False)
(ergibt "A8")
Zugriff auf Spalten oder Zeilen
Löschen von Spalten: Columns("B:D").Delete
Range(„B:D“).Delete
Das Gleiche gilt für Zeilen: Rows(„1:3“).Delete
Range(„1:3“).Delete
Zugriff auf Zellen und Bereiche
Seite 16 von 74 Version 3.2 / 14.10.2014 © 2014 Daniel Hofer
Performance-Vergleich
Im Folgenden schauen wir nur ganz kurz die Performance an, wenn wir in 1000 Zeilen und 100 Spalten die Zahl 3 eintragen wollen.
Schlechteste Variante mit Cell.Select
For vSpalte = 1 to 100
For vZeile = 1 to 1000
Cells(vZeile,vSpalte).Select
Selection.Value = 3
Next vZeile
Next vSpalte
Dieses Beispiel hat rund 3min zum Durchlaufen
Dito, aber mit Application.ScreenUpdating = False
Application.ScreenUpdating = False
For vSpalte = 1 to 100
For vZeile = 1 to 1000
Cells(vZeile, vSpalte).Select
Selection.Value = 3
Next vZeile
Next vSpalte
Application.ScreenUpdating = True
Dieses Beispiel hat ca. 17 Sekunden!
Auf Cell.Select verzichten
For vSpalte = 1 to 100
For vZeile = 1 to 1000
Cells(vZeile, vSpalte).Value = 3
Next vZeile
Next vSpalte
Diese Version hat 19 Sekunden. Ist also interessanterweise 2 Sekunden
langsamer als das „schlechte“ Select, wenn dort ScreenUpdating = False
definiert ist
Auf Cell.Select verzichten, ScreenUpdating ausschalten
Application.ScreenUpdating = False
For vSpalte = 1 to 100
For vZeile = 1 to 1000
Cells(vZeile, vSpalte).Value = 3
Next vZeile
Next vSpalte
Application.ScreenUpdating = True
Zugriff auf Zellen und Bereiche
© 2014 Daniel Hofer Version 3.2 / 14.10.2014 Seite 17 von 74
Diese Version ist noch ein wenig schneller, und zwar braucht sie rund 6-7
Sekunden.
Gleichzeitig mehrere Excel-Dateien offen
Vorsicht! Sind zwei Excel-Dateien geöffnet (und egal, ob die andere VBA-Code
enthält oder nicht), dann wird die Abarbeitung des Codes extrem viel
langsamer! Also bei Zeit-intensiven Abläufen immer nur eine Datei geöffnet
haben.
Vergleich IF und SELECT CASE
If x = 1 then…
If x = 2 then…
If x = 3 then
ist rund doppelt so langsam wie:
Select Case x
Case 1: …
Case 2: …
Case 3: …
End Select
Wobei folgende Anweisung im schlechtesten Fall gleich schnell wie die SELECT-
Anweisung, aber im besten Fall doppelt so schnell wie diese ist:
If x = 1 then…
Elseif x = 2 then…
Elseif x = 3 then…
Variablenvergleich
If intVariable = 32 then
blnTest = True
Else
blnTest = False
End If
ist rund doppelt so langsam wie:
blnTest = (intVariable = 32)
Boolean-Variable drehen
Eine nicht selten gesehendes Szenario ist:
If blnTest = True then
blnTest = False
Else
blnTest = True
End if
Doppelt so schnell geht’s mit
Zugriff auf Zellen und Bereiche
Seite 18 von 74 Version 3.2 / 14.10.2014 © 2014 Daniel Hofer
blnTest = not blnTest
Potenzieren
vTest = vTest^2 ist sage und schreibe rund 5x (fünf!)
langsamer als:
vTest=vTest*vTest
Variant wenn möglich vermeiden
Der Datentyp Variant unter VBA sollte wenn möglich vermieden werden. Dies
ist allerdings nicht immer möglich, z.B. beim Abfangen der Inputbox auf Seite
39.
Der Makrorekorder
Der Makrorekorder von Excel ist einerseits in Programmierkreisen verpönt, andererseits wird er von VBA-Einsteigern häufig eingesetzt. Ich zeigen Ihnen hier, welcher Einsatzzweck des Rekorders Sinn macht, und wie Sie häufige Probleme beheben können.
Unsinniger Einsatz des Rekorders
Sie zeichnen einen Ablauf mit dem Rekorder auf, und weisen dem Makro am
Schluss noch einen Button zu. Danach verwenden Sie das Makro blind, ohne es
zu vorgängig zu kontrollieren.
Dies ist die übliche Art, wie Einsteigerinnen und Einsteiger mit Makros
umgehen. Einfach etwas aufzeichnen und dies dann ungefragt einsetzen.
Das wird nie gut kommen. Sie müssen immer Ihr aufgezeichnetes Makro
nachträglich kontrollieren und unsinnige Teile rauslöschen.
Sinnvolle Einsatzmöglichkeiten des Rekorders
Sie wissen als Beispiel nicht, wie man die Hintergrundfarbe auf ein schönes Rot
ändert. Dazu verwenden Sie den Rekorder:
Starten Sie den Rekorder mit den Standardeinstellungen:
Zugriff auf Zellen und Bereiche
© 2014 Daniel Hofer Version 3.2 / 14.10.2014 Seite 19 von 74
Ändern Sie die Hintergrundfarbe auf rot:
Stoppen Sie sofort den Makrorekorder wieder
Jetzt wechseln Sie in den VBA-Editor und suchen das aufgezeichnete Makro:
In meinem Fall hat Excel dem Makro resp. der Prozedur den Namen Makro1
gegeben. Und Sie sehen, dass hier ziemlich viel drin steht. Das Einzige, was uns
aber interessiert, ist die Eigenschaft Color = 255 (Hinweise zu WITH siehe Seite
32).
Sie können diese Eigenschaft kopieren resp. sich merken und an der
gewünschten Stelle in Ihrem anderen Code fügen Sie diese Eigenschaft so ein.
Als Beispiel:
Selection.Interior.Color = 255
oder als Alternative:
ActiveCell.Interior.Color = 255
Oder Sie greifen direkt auf eine Zelle zu:
Range(„A1“).Interior.Color = 255
resp.
Cells(1,1).Interior.Color = 255
Zugriff auf Zellen und Bereiche
Seite 20 von 74 Version 3.2 / 14.10.2014 © 2014 Daniel Hofer
Nachträgliche Korrekturen nach dem Aufzeichnen
Möchten Sie den Makrorekorder nicht nur dazu verwenden, um rasch
rauszufinden, wie man wohl die Hintergrundfarbe ändert, sondern vielleicht
auch mehr damit anstellen, dann ist es zwingend, dass Sie den Code
kontrollieren.
Beispiel 1
Bereits beim obigen Beispiel, als Sie lediglich die Hintergrundfarbe auf rot
geändert haben, zeichnete der Makrorekorder viel mehr auf:
With Selection.Interior
.Pattern = xlSolid
.PatternColorIndex = xlAutomatic
.Color = 255
.TintAndShade = 0
.PatternTintAndShade = 0
End With
Hier müssen Sie realisieren, dass Sie eben nur die Zeile mit der Eigenschaft
Color benötigen.
Beispiel 2
Ein schlimmeres Beispiel zeigt das Einfügen einer Rahmenlinie unten:
Zeichnen Sie nämlich den Klick darauf auf, dann sieht der Code wie folgt aus:
Selection.Borders(xlDiagonalDown).LineStyle = xlNone
Selection.Borders(xlDiagonalUp).LineStyle = xlNone
Selection.Borders(xlEdgeLeft).LineStyle = xlNone
Selection.Borders(xlEdgeTop).LineStyle = xlNone
With Selection.Borders(xlEdgeBottom)
.LineStyle = xlContinuous
.ColorIndex = 0
.TintAndShade = 0
.Weight = xlThin
End With
Selection.Borders(xlEdgeRight).LineStyle = xlNone
Selection.Borders(xlInsideVertical).LineStyle =
xlNone
Selection.Borders(xlInsideHorizontal).LineStyle =
xlNone
Zugriff auf Zellen und Bereiche
© 2014 Daniel Hofer Version 3.2 / 14.10.2014 Seite 21 von 74
Und genau hier haben wir ein Problem. Wir haben lediglich eine Rahmenlinie
unten einfügen wollen. Aber mit diesem Code werden sämtliche andere
Rahmenlinien in einer Zelle ausgeschaltet. Dies wollten wir aber nicht.
Stellen Sie sich vor, Sie hätten bereits eine Zelle mit einer Rahmenlinie links
und oben:
Führen Sie den aufgezeichneten Code aus, entfernt Ihnen das Makro diese
beiden Rahmenlinien. Das war aber ganz und gar nicht das, was wir wollten.
Deshalb müssen Sie auch hier das Makro anpassen, damit nur noch die Zeilen
übrig bleiben, die Sie wollen. Also hier als Beispiel:
With Selection.Borders(xlEdgeBottom)
.LineStyle = xlContinuous
.ColorIndex = 0
.TintAndShade = 0
.Weight = xlThin
End With
Beispiel 3
Fügen Sie mittels Makrorekorder unter Excel 2013 ein Diagramm ein, wird
folgender (eigentlich sehr schlanker) Code erzeugt: ActiveSheet.Shapes.AddChart2(201, xlColumnClustered).Select
ActiveChart.SetSourceData Source:=Range("Tabelle2!$B$2:$G$6")
Schauen Sie die zweite Code-Zeile an. Da müssen Sie definitiv den Bereich für
eine spätere Verwendung anpassen.
Tabellenblätter / Dateien
Seite 22 von 74 Version 3.2 / 14.10.2014 © 2014 Daniel Hofer
Tabellenblätter / Dateien
Neues Tabellenblatt hinzufügen (standardmässig VOR dem aktuellen)
Fokus wird auf das neue Sheet gewechselt Worksheets.Add
Neues Tabellenblatt hinzufügen (NACH dem aktuellen)
Fokus wird auf das neue Sheet gewechselt Worksheets.Add , ActiveSheet
Namen des aktuellen Sheets ändern
ActiveSheet.Name = "Gugus"
Neues Sheet, danach Fokus wieder auf das alte Sheet zurück
Dim wks As Worksheet
Set wks = ActiveSheet
Worksheets.Add , ActiveSheet
ActiveSheet.Name = "Gugus1"
wks.Select
Worksheets löschen
Dim wks As Worksheet
For Each wks In Worksheets
wks.Delete
Next
Worksheets löschen
Warnmeldung ist deaktiviert. Das letzte Worksheet wird nicht gelöscht ( Fehlermeldung) Dim wks As Worksheet
Application.DisplayAlerts = False
For Each wks In Worksheets
If Worksheets.Count = 1 Then Exit Sub
wks.Delete
Next
Application.DisplayAlerts = True
Excel-Dokumente speichern
Anzeigen eines Speichern-Dialogs
Dafür gibt es 2 Möglichkeiten:
Application.Dialogs(xlDialogSave).Show
dies ist die schlechte Variante. Beim Klick auf den Button "Speichern" wird die
Datei effektiv gerade physisch gespeichert
Die bessere Variante:
Tabellenblätter / Dateien
© 2014 Daniel Hofer Version 3.2 / 14.10.2014 Seite 23 von 74
vFile = _
Application.GetSaveAsFilename(FileFilter:="Microsoft
Excel-Dateien (*.xl*), *.xl*")
If vFile <> False then
MsgBox vFile
End If
Die Methode "GetSaveAsFilename" des Application-Objekts gibt lediglich den
Namen zurück. Was mit diesem Namen danach gemacht wird, müssen WIR
entscheiden.
Speichern der aktuellen Datei
Da Office 2007 im Application-Objekt keine FileSearch-Methode mehr kennt,
müssen wir auf die Scripting Runtime Bibliothek integrieren (siehe "Scripting
Runtime" im Kapitel "Diverses")
Dim vFS As New FileSystemObject
On Error Resume Next
vFS.CreateFolder "C:\hallo"
On Error GoTo 0
If vFS.FileExists("c:\hallo\gugus.xlsm") = False Then
ActiveWorkbook.SaveAs "c:\hallo\gugus.xlsm",
xlOpenXMLWorkbookMacroEnabled
Else
ActiveWorkbook.Save
End If
Achtung!
Microsoft Access bietet im Application-Objekt weder eine Auflistung „Dialogs“
noch eine Methode „GetSaveAsFilename“. Der Grund liegt darin, dass eine
Access-Datenbank nicht im gleichen Sinne gespeichert wird wie ein Word- oder
Excel-Dokument.
In Access will man häufig die Datenbank resp. die komplette Applikation
schliessen, und dabei gleich speichern. Das würde so aussehen:
Application.Quit acQuitSaveAll
Excel-Dateien öffnen
In der einfachsten Variante wird ein einzelnes Excel-Dokument wie folgt geöffnet: Workbooks.Open(Filename:="D:\Daten\Kunden1.xlsx")
Jetzt haben wir aber meist ein Problem: wir haben 2 Dateien gleichzeitig offen. Was geschieht nun, wenn wir z.B. ein Cells(1,1) = „Hallo“
schreiben? In welche Datei und in welches Tabellenblatt schreibt das VBA rein?
Tabellenblätter / Dateien
Seite 24 von 74 Version 3.2 / 14.10.2014 © 2014 Daniel Hofer
Ganz einfach: in das gerade offene und aktive. Und genau das wollen wir häufig nicht! Aus diesem Grund müssen wir bei jedem Zugriff auf ein Excel-Objekt die Mappe und das Tabellenblatt sauber angeben. Also anstelle Cells(1,1) = „Hallo“
schreiben wir: Workbooks(„Kunden1.xlsx“).Worksheets(„Tabelle1“).Cells(
1,1) = „Hallo“
Korrekterweise sollten wir nicht einfach eine Excel-Mappe öffnen, sondern diese gleich in einer entsprechenden Variable speichern: Dim objSource As Workbook
Set objSource =
Workbooks.Open(Filename:="D:\Daten\Kunden1.xlsx")
Ab sofort können wir auf die Variable objSource zugreifen: objSource.Sheets("Tabelle1").Cells(1,1) = „Hallo“
Nach unseren Arbeiten wollen wir vielleicht die Datei speichern: objSource.Save
Oder wir wollen sie schliessen ohne zu speichern: objSource.Close False
Damit dies aber keine lästige Nachfrage bringt, schalten wir die Warnmeldungen kurz aus: Application.DisplayAlerts = False
objSource.Close False
Application.DisplayAlerts = True
Achtung! Diese gleich wieder einschalten danach! Sonst wird’s gefährlich!
Öffnen-Dialog anzeigen
Der Öffnen-Dialog kriegen wir so hin: Dim vFile As String
vFile = Application.GetOpenFilename()
Diese Variante lässt nur die Auswahl einer einzigen Datei.
Tabellenblätter / Dateien
© 2014 Daniel Hofer Version 3.2 / 14.10.2014 Seite 25 von 74
Öffnen-Dialog und darin mehere Dateien auswählen
Wollen wir im Öffnen-Dialog gleich mehere Dateien auswählen, dann sieht der Code so aus: (diesmal als vollständige Prozedur)
Beachte, dass diesmal vFile als Variant deklariert ist. Die Methode GetOpenFilename kann nämlich entweder ein FALSE zurückgeben, falls man den Dialog abbricht, oder aber ein Array von Einträgen (siehe Kapitel Arrays, Seite 31)
Neue Excel-Mappe erstellen
Eine Excel-Mappe lässt sich ganz einfach mit Workbooks.Add
erstellen. Aber vorsicht! Bitte nie so machen. Excel öffnet dann zwar eine neue leere Arbeitsmappe und aktiviert diese. Aber wir haben mit VBA dann keinen sauberen Zugriff mehr drauf. Plötzlich machen wir mittels VBA Änderungen in der falschen Mappe (und das wäre ärgerlich…)! Besser ist es, gleich eine Objektvariable sauber zu definieren: Dim vWB As Workbook
Set vWB = Workbooks.Add
Jetzt haben wir sauber eine Variable vWB, mit welcher wir arbeiten können. Es ist nämlich einen himmelweiten Unterschied, ob wir unsere neue Mappe so speichern: ActiveWorkbook.Save
oder so: vWB.Save
Bei der ersten Version hoffen wir einfach, dass die gerade aktive Mappe die vorher neu erstellte ist. Bei der zweiten Version wissen wir, was wir tun.
VBA-Grundlagen
Seite 26 von 74 Version 3.2 / 14.10.2014 © 2014 Daniel Hofer
VBA-Grundlagen
Variablen
Variablen sind global definiert
Das heisst, sie sind erreichbar von beiden Prozeduren
Prozedur „Subtrahiere“ überschreibt den Wert von C!
Dim a, b, c As Integer
Sub Addiere()
a = 1
b = 3
c = a + b
Subtrahiere
End Sub
Sub Subtrahiere()
c = a - b
End Sub
Variablen sind nur innerhalb der Prozedur „Addiere“ sichtbar.
Sie müssten in der Prozedur „Subtrahiere“ neu definiert werden
Kein Überschreiben der Variablen möglich
Sub Addiere()
Dim a, b, c As Integer
a = 1
b = 3
c = a + b
Call Subtrahiere
End Sub
vUebergabe in „Transfer“ wird durch „Addiere“ überschrieben
Variablenübergabe standardmässig „ByRef“
Sub Transfer()
Dim vUebergabe As Integer
vUebergabe = 10
Addiere vUebergabe
Debug.Print vUebergabe
End Sub
Sub Addiere(vEmpfange As Integer)
VBA-Grundlagen
© 2014 Daniel Hofer Version 3.2 / 14.10.2014 Seite 27 von 74
vEmpfange = vEmpfange + 5
End Sub
vUebergabe bleibt bis am Schluss 10, da die Variable als Wert, und nicht
als Pointer resp. als Referenz auf die entsprechende Speicherstelle,
übergeben wird.
Sub Transfer()
Dim vUebergabe As Integer
vUebergabe = 10
Addiere vUebergabe
Debug.Print vUebergabe
End Sub
Sub Addiere(ByVal vEmpfange As Integer)
vEmpfange = vEmpfange + 5
End Sub
ByRef wäre normal, allerdings wird der Parameter der Prozedur in
Klammern aufgerufen.
Somit findet eine ByVal-Übergabe statt
vUebergabe wird nicht überschrieben
Sub Transfer()
Dim vUebergabe As Integer
vUebergabe = 10
Addiere (vUebergabe)
Debug.Print vUebergabe
End Sub
Sub Addiere(vEmpfange As Integer)
vEmpfange = vEmpfange + 5
End Sub
Wird zusätzlich zu den eckigen Klammern der Aufruf mittels dem
Schlüsselwort „CALL“ gemacht, findet das Ganzw wieder ByRef statt.
vUebergabe wird überschrieben
Sub Transfer()
Dim vUebergabe As Integer
vUebergabe = 10
Call Addiere(vUebergabe)
Debug.Print vUebergabe
End Sub
Sub Addiere(vEmpfange As Integer)
vEmpfange = vEmpfange + 5
VBA-Grundlagen
Seite 28 von 74 Version 3.2 / 14.10.2014 © 2014 Daniel Hofer
End Sub
Variablendeklaration korrekt
Dim vGanzeZahl as integer
Variablendeklarationen falsch
Fehlt der Typ, wird automatisch „Variant“ genommen
Dim vGanzeZahl
Dim vGanzeZahl% Abkürzung für Integer
Dim vNachname
Dim vNachname$ Abkürzung für String
Warum nicht Variant als Typ einsetzen?
Integer benötigt 2 Bytes
Double benötigt 8 Bytes
Variant benötigt in JEDEM Fall 16 Bytes
Aufzählungen (Enumerationen)
Definition
Enum SchuelerQualitaet
sqSaumässigSchlecht = 1
sqNaEsGehtSo = 2
sqGarNichtMalSoSchlecht = 3
sqWowDerTypHatsDrauf = 4
End Enum
Sub Transfer()
Dim vSchuelerQualitaet As SchuelerQualitaet
vSchuelerQualitaet = sqGarNichtMalSoSchlecht
End Sub
Ansicht im Code bei der Variablen-Deklaration
VBA-Grundlagen
© 2014 Daniel Hofer Version 3.2 / 14.10.2014 Seite 29 von 74
Ansicht im Code bei der Variablenzuweisung
Konstanten
Konstanten, falsch definiert
Const mwst = 0.076
Konstanten, korrekt definiert
Konstanten-Name GROSS
Konstante mit dem korrekten Typ deklarieren!
Const MWST as double = 0.076
Funktionen
Die Funktion überschreibt die Variable der Prozedur „Transfer1“.
Dies ist sehr schlecht! Das darf so nicht geschehen.
Sub Transfer1()
Dim vErsteZahl As Double, vZweiteZahl As Double,
vResultat As Double
vErsteZahl = 55
vZweiteZahl = 35
Debug.Print "vErsteZahl: " & vErsteZahl
Debug.Print "vZweiteZahl: " & vZweiteZahl
vResultat = fMittelwert(vErsteZahl, vZweiteZahl)
Debug.Print "vErsteZahl: " & vErsteZahl
Debug.Print "vZweiteZahl: " & vZweiteZahl
End Sub
Function fMittelwert(vZahl1 As Double, vZahl2 As
Double) As Double
fMittelwert = (vZahl1 + vZahl2) / 2
vZahl1 = 99
End Function
VBA-Grundlagen
Seite 30 von 74 Version 3.2 / 14.10.2014 © 2014 Daniel Hofer
Funktionsdeklaration korrekt
Funktionsname mit Sinn und „f“ als Präfix
vGebDat ist korrekt deklariert
Rückgabewert ist korrekt deklariert
Function fGetAlter(vGebDat as date) as integer
End Function
Funktionsdeklaration falsch
Präfix „int“ soll entweder bei Variablen ODER bei Funktionen verwendet
werden, aber nicht an beiden Orten
Die Typendeklaration mit % ist unschön und nicht leserlich
Function intGanz%(a%)
End Function
Optionale Parameter
Der dritte Parameter wird als optional definiert
Function fMittelwert(vZahl1 As Double, vZahl2 As _
Double, Optional vZahl3 as Double) As Double
Andere Reihenfolge der Parameter
Durch die Angabe des Parameter-Namens plus „:=“ können die Parameter
beliebig in der Reihenfolge gewählt werden
Anstelle
vResultat = fMittelwert(vErsteZahl, vZweiteZahl)
können die Parameter benannt, und entsprechend die
Reihenfolge vertauscht werden:
vResultat = fMittelwert(vZahl2:=vZweiteZahl,
vZahl1:=vErsteZahl)
Gültigkeitsbereiche
Variable ist im gleichen Modul von allen Funktionen und Prozeduren
aus zu sehen und änderbar
Aus einem anderen Modul ist die Variable allerdings nicht sichtbar
Dim vAlter as integer
Modul1:
Sub pTestprozedur()
VBA-Grundlagen
© 2014 Daniel Hofer Version 3.2 / 14.10.2014 Seite 31 von 74
End Sub
Sub pTestprozedur2()
End Sub
Variable ist durch die Kennung „Global“ aus allen Modulen sichtbar
Global vAlter as integer
Modul1: Modul2:
Sub pTestprozedur() Sub pTestprozedur2()
End Sub End Sub
Falsche Deklaration
Eine „Global“-Deklaration innerhalb einer Prozedur ist nicht möglich, und führt
entsprechend zu einem Fehler
Sub pTestprozedur()
Global vAlter as integer
End Sub
„Private“ macht, dass die Prozedur in der Excel-Makroliste nicht
erscheint
Private Sub Workbook_Open()
End Sub
Arrays
Arrays werden in VBA als "Felder" bezeichnet.
Deklaration einer fixen Grösse
Dim vMonate(12) As String
Dim i As Integer
For i = 1 To 12
vMonate(i) = Format(DateSerial(2008, i, 1),
"MMMM")
Next
Diese Variante funktioniert, wenn wir die Grösse eines Arrays fix vorhersagen
können.
VBA-Grundlagen
Seite 32 von 74 Version 3.2 / 14.10.2014 © 2014 Daniel Hofer
Deklaration einer unbestimmten Grösse
Häufig wissen wir nicht, wie gross ein Array wird. In diesem Fall müssen wir die
Grösse bei der Deklaration nicht bestimmen. Vor dem eigentlichen Gebrauch
der Variablen müssen wir die Grösse allerdings angeben.
Dim a() as integer
Beim ersten Gebrauch verwenden wir:
Redim a(10)
Achtung! Der Inhalt des Arrays wird gelöscht!
Stellen wir fest, dass das Array noch zu klein war, definieren wir es neu,
allerdings macht es Sinn, hier das Schlüsselwort "preserve" einzusetzen:
Redim preserve a(20)
So werden die bestehenden Einträge im Array nicht gelöscht.
Array-Inhalt löschen
Erase vMonate()
Untere und obere Grenze eines Arrays ausgeben
Debug.Print LBound(vMonate())
Debug.Print UBound(vMonate())
Unterer Arraywert beginnt bei 0
Definieren wir ein Array
Dim a(10) as integer
enthält dieses Array 11 Speicherplätze, da die Zählung bei 0 beginnt.
Wollen wir dies verhindern, müssen wir in einem Modul zuoberst folgendes
eintragen:
Option Base 1
WITH
Vor allem beim Aufzeichnen mit dem Makro-Rekorder entdeckt man häufig Code wie der folgende: With Selection.Interior
.Pattern = xlSolid
.PatternColorIndex = xlAutomatic
.Color = 65535
.TintAndShade = 0
.PatternTintAndShade = 0
End With
Dieser Codeblock dient lediglich als Abkürzung und besserer Lesbarkeit. Hätten wir das WITH nicht, müssten wir obigen Code so schreiben: Selection.Interior.Pattern = xlSolid
Selection.Interior.PatternColorIndex = xlAutomatic
VBA-Grundlagen
© 2014 Daniel Hofer Version 3.2 / 14.10.2014 Seite 33 von 74
Selection.Interior.Color = 65535
Selection.Interior.TintAndShade = 0
Selection.Interior.PatternTintAndShade = 0
Wir müssen also das Objekt Selection.Interior jedes Mal wiederholen. Wenn wir in einer Zelle resp. in einem Bereich viel anpassen, dann wird der Code recht unleserlich. Wir können jederzeit selber entscheiden, ob wir mittels WITH abkürzen wollen oder nicht.
MsgBox
Die Messagebox ist ein Windows Meldefenster, welches z.B. so aussehen kann:
Wir benötigen dies immer, wenn wir mit unseren Benutzerinnen und Benutzer kommunizieren wollen. Das heisst, immer dann, wenn wir ihnen eine böse Fehlermeldung mitteilen wollen, oder sie auffordern wollen, etwas zu tun, oder wenn wir von ihnen eine Frage beantwortet haben möchten.
MsgBox als Prozedur
Der einfachste Aufruf sieht so aus:
MsgBox "Bitte auf OK klicken"
Dann erscheint obige Meldung. Als Variante können wir als zweiten Parameter
z.B. ein Zeichen einblenden:
MsgBox "Bitte auf OK klicken", vbCritical
Nun erscheint die gleiche Meldung, aber:
Wir haben bei dieser Art Messagebox keine Möglichkeit, auf die Eingabe der
Anwender zu reagieren. Wir können zwar folgende Messagebox bringen:
MsgBox "Willst du wirklich alle Daten löschen?",
vbYesNo
VBA-Grundlagen
Seite 34 von 74 Version 3.2 / 14.10.2014 © 2014 Daniel Hofer
Was uns folgendes Fenster beschert:
Wir können aber nicht rausfinden, ob die Person JA oder NEIN geklickt hat. Und
aus diesem Grund verwendet man die MsgBox häufig als Funktion anstelle
Prozedur.
MsgBox als Funktion
Verwenden wir die MsgBox-Funktion, dann erwarten wir von ihr eine Antwort
zurück. Dafür definieren wir zuerst eine Integer-Variable vResult. Entsprechend
wird dann nach dem Aufruf der MsgBox-Funktion diese Variable mit einem
Wert gefüllt:
Dim vResult As Integer
vResult = MsgBox("Willst du wirklich alle Daten
löschen?", vbYesNo)
Hat die Person auf JA geklickt, steckt in der Variable vResult der Wert 6 drin
(das finden wir in der Online-Hilfe).
Also können wir nach obigem Aufruf danach abfragen:
If vResult = 6 Then
Range("A:F").ClearContents
End If
vb-Konstanten
Microsoft hat, damit man sich wie beim obigen Beispiel nicht solche Zahlen wie 6 für den Knopf JA merken muss, Konstanten vordefiniert. Diese beginnen alle mit den beiden Buchstaben vb… Obiges MsgBox-Beispiel wird sofort lesbarer, wenn wir eben mit einer solchen Konstante arbeiten können: If vResult = vbYes Then
Range("A:F").ClearContents
End If
VBA-Grundlagen
© 2014 Daniel Hofer Version 3.2 / 14.10.2014 Seite 35 von 74
Schleifen
Es gibt 3 Schleifentypen:
For Next
Do Loop
While Wend
For Next
Diese Schleife wird verwendet, wenn die Anzahl der Durchgänge bekannt ist.
For i = 1 to 12
Cells(i,1) = Format(DateSerial(2008, i, 1), "MMMM")
Next i
Diese Schleife kann mit
Exit For
verlassen werden.
While Wend
Diese Schleife wir bei Nichterfüllen der Bedinung NIE ausgeführt:
While i < 13
Cells(i,1) = Format(DateSerial(2008, i, 1), "MMMM")
i = i + 1
Wend
Diese Schleife kann nicht verlassen werden!
Do Loop
Hier gibt es 2 Möglichkeiten:
Bedingung am Anfang prüfen (bei Nichterfüllung kein Durchlaufen,
identisch mit While Wend)
Bedingung am Schluss prüfen (ein Durchlaufen ist zwingend)
Bedingung am Anfang prüfen:
Do While i < 13
Cells(1,i) = Format(DateSerial(2008, i, 1), "MMMM")
i = i + 1
Loop
Bedingung am Schluss prüfen
Do
Cells(i,1) = Format(DateSerial(2008, i, 1), "MMMM")
i = i + 1
Loop Until I > 12
Do Loop Schleifen können verlassen werden.
VBA-Grundlagen
Seite 36 von 74 Version 3.2 / 14.10.2014 © 2014 Daniel Hofer
: Performance-mässig wird entweder die For Next oder die Do
Loop Schleife empfohlen
Zellzugriff mit Range
Wollen Sie obige Beispiele nicht mittels der Cells-Auflistung, sondern mit Range
lösen, dann schreiben Sie das wie folgt (am Beispiel der For-Schleife): For i = 1 to 12
Range(„A“ & i) = Format(DateSerial(2008, i, 1), "MMMM")
Next i
VBA-Grundlagen
© 2014 Daniel Hofer Version 3.2 / 14.10.2014 Seite 37 von 74
Fehler-Behandlung (z.B. InputBox)
Standard-Fehlerbehandlung in einer Prozedur
Am Anfang einer Prozedur wird mit „On Error…“ definiert, was geschehen soll,
wenn ein Laufzeit-Fehler auftaucht.
Im folgenden Beispiel wird zur Sprungmarke „err_pTest“ gesprungen.1
Sub pTest
On Error Goto err_pTest
Debug.Print „Hallo“
goto exit_pTest wichtig!
err_pTest:
MsgBox err & “ “ & err.Description
exit_pTest:
End Sub
(Achtung! die Zeile “goto exit_pTest“ muss sein, sonst wird die
Fehlerbehandlung abgearbeitet, was wenig Sinn macht.
Alternative zur „goto“-Anweisung
Eine Alternative mit dem „goto exit_pTest“ ist folgende Variante:
Sub pTest
On Error Goto err_pTest
Debug.Print „Hallo“
exit Sub
err_pTest:
MsgBox err & “ “ & err.Description ‘offizieller
Fehler von MS
MsgBox „Lieber User. Da ging leider was schief…“
End Sub
Anstelle eines „goto“-Befehls wird die Prozedur einfach mit einem „exit Sub“
verlassen. Die Meinungen gehen hier auseinander, was besser ist. Ich finde
grundsätzlich „Exit“-Anweisung nicht so toll. Andere finden dafür „Goto“-
Anweisungen schlecht.
1 auch hier macht eine saubere Namenskonvention Sinn! err als Präfix, danach der Name der Prozedur resp. Funktion.
VBA-Grundlagen
Seite 38 von 74 Version 3.2 / 14.10.2014 © 2014 Daniel Hofer
Fehler ignorieren
Sollen Fehler ignoriert werden, schreiben wir
On Error resume next
Achtung! Diese Zeile nicht am Anfang einer Prozedur einsetzen, sondern
wirklich nur vor der Anweisung, bei der wir wissen, dass sie einen Fehler
verursacht, und dies uns egal ist
Sub pTest
On Error Goto err_pTest
Debug.Print „Hallo“
On Error Resume Next
Debug.print 100/0 ‘erzeugt Fehler “Division durch 0
Sheets("Tabelle1").Delete ‘Vielleicht gibt’s die
Tabelle gar nicht
On Error Goto err_pTest ‘Muss sein!2
Debug.Print “Hallo”
exit Sub
err_pTest:
MsgBox err & “ “ & err.Description
End Sub
Fehlerbehandlung auf VBA-Standard zurücksetzen
Folgende Anweisung setzt die Fehlerbehandlung auf den Original-Zustand
zurück:
On Error goto 0
Vorsicht! Die benutzerdefinierte Fehlerbehandlung ist nun ausgeschaltet!
Besser als Fehler ignorieren
Obige Methode zum Ignorieren einer einzelnen Zeile ist zwar üblich, aber es
geht noch ein wenig schöner. Und zwar, wenn wir erst in der Fehler-
Behandlung den Fehler abfragen:
Sub pTest
On Error Goto err_pTest
Debug.Print „Hallo“
On Error Resume Next
Debug.print 100/0 ‘erzeugt Fehler “Division durch 0
On Error Goto err_pTest
Debug.Print “Hallo”
2 Nach der Fehler-trächtigen Zeile wollen wir unsere Fehler-Behandlung wieder aktivieren
VBA-Grundlagen
© 2014 Daniel Hofer Version 3.2 / 14.10.2014 Seite 39 von 74
exit Sub
err_pTest:
If err = 11 then ‘Division durch 0
Resume Next
Else
MsgBox err & “ “ & err.Description
End If
End Sub
So ignorieren wir nicht jeden beliebigen Fehler (was wir mit “On Error resume
next” machen), sondern ignorieren lediglich den Laufzeitfehler 11.
Dies ist wohl die sauberste Variante.
InputBox sauber abfangen
Das Aufrufen einer InputBox ist zwar äusserst bequem, aber sehr heikel.
Erscheint nämlich folgende Box:
Dann können die Anwenderinnen und Anwender nämlich irgend einen Blödsinn
eingeben. Auch wenn wir vielleicht eine Zahl wünschen. Im Folgenden zeige ich
drei Möglichkeiten auf, wie das Abfragen nach einer Zahl möglich ist.
Der Probleme verursachende Code ist folgender:
Falls ein String daher kommt, kriegen wir einen Laufzeitfehler.
Version 1, mit der Funktion IsNumeric()
VBA-Grundlagen
Seite 40 von 74 Version 3.2 / 14.10.2014 © 2014 Daniel Hofer
Wir benötigen zuerst eine neue Variable, welche als String definiert ist. Erst
danach schauen wir, ob sich diese Variable in eine Zahl umwandeln lassen
würde. Dies geschieht mit der Funktion IsNumeric(). Diese Version ist in der
Regel die beste.
Version 2, mit der Methode Application.InputBox
Anstelle der Funktion InputBox() nehmen wir die Methode InputBox des
Objekts Application:
Hier sehen wir gelb markiert, dass man den Typ mitgeben kann. Type=1
heisst, Excel kontrolliert, dass man nur Zahlen eingibt.
Hinweis: Weder Word noch Access kennen die Methode Inputbox des
Application-Objekts!
Es erscheint sonst automatisch folgende Meldung:
¨
Version 3, mit Error-Handling
Dies ist die unschönste Version, aber manchmal trotzdem elegant:
VBA-Grundlagen
© 2014 Daniel Hofer Version 3.2 / 14.10.2014 Seite 41 von 74
Mit der ersten rot markierten Zeile wird quasi die interne Error-Meldung von
VBA ausgeschaltet. Danach produzieren wir einen Fehler, weil wir der
Variablen vRadius einen String übergeben wollen (aber es erscheint keine
interne Fehlermeldung durch unser Ausschalten). Nun fragen wir in der gelb
markierten Zeile ab, ob eventuell der Fehler 13 aufgetreten ist (Typen
unverträglich). Wenn ja, reagieren wir wieder entsprechend drauf.
Wichtig! Das Error-Handling muss unbedingt wieder eingeschaltet werden!
(zweite rot markierte Zeile)
VBA-Grundlagen
Seite 42 von 74 Version 3.2 / 14.10.2014 © 2014 Daniel Hofer
Text-Funktionen
Text-Funktionen in VBA werden sehr häufig benötigt. Unter Excel existieren auch solche Funktionen wie:
TEIL
LINKS
RECHTS
LAENGE
etc.
Haben wir als Beispiel eine Liste in Excel, welche eine Spalte mit Vor- und Nachnamen enthält:
Wir möchten diese Spalte auftrennen in zwei separate Spalten, dann werden obige Funktionen häufig benötigt (wir können natürlich auch den Assistenten „Text in Spalten“ verwenden, aber ev. wollen wir ja nicht jeden Tag diese Arbeiten manuell durchführen, sondern einen gewissen Automatismus für uns arbeiten lassen. Unter VBA brauchen wir diese Funktionen für die gleichen Arbeiten. Vielleicht rattern wir ja die Excel-Liste mittels einer Schleife von oben nach unten durch und ändern das Ganze mittels einer VBA-Funktion.
Warum mit VBA und nicht mit TEIL, LINKS, SUCHEN, etc.?
Tabellenfunktionen in Excel werden häufig, sobald sie verschachtelt sind,
extrem unübersichtlich. Ein VBA-Programm ist in den allermeisten Fällen viel
lesbarer und übersichtlicher.
Text-Funktionen im Überblick
Für die folgenden Beispielen arbeiten wir mit folgenden Variablen:
vName=“Müller Fritz“
vNachname = „“
vVorname = „“
vLaenge = 0
Unter VBA heissen diese Funktionen wie folgt:
Funktion Beschreibung / Beispiel
VBA-Grundlagen
© 2014 Daniel Hofer Version 3.2 / 14.10.2014 Seite 43 von 74
Funktion Beschreibung / Beispiel
Left Gibt von einem String von links an gerechnet die angegebenen Zeichen zurück. vNachname = Left(vName,6)
Right Gibt von einem String von rechts an gerechnet die angegebenen Zeichen zurück. vVorname = Right(vName,5)
Len Gibt die Länge eines Strings zurück. vLaenge = Len(vNachname)
Mid Gibt von einem String gewisse Zeichen zurück. Im Gegensatz zu Left oder Right kann man hier irgendwo starten. Debug.Print Mid(vName, 3, 4)
Ergibt:
Trim Entfernt in einem String die führenden resp. nachfolgenden
Leerzeichen und gibt das Resultat als String zurück. vNameSauber = Trim(„ Hans Huber „)
In vNameSauber steckt nun korrekt: „Hans Huber“
InStr Sucht einen bestimmten Text und gibt die Position zurück. vPos = InStr(1, vName, " ", vbTextCompare)
gibt die Zahl 7 zurück, weil der Leerschlag an Pos. 7 von links steckt.
InStrRev Gleich wie InStr, nur dass von rechts mit der Suche begonnen wird. Achtung! Die Syntax ist nicht gleich wie bei InStr. Hier beide Funktionen im Vergleich:
Die erste beginnt ganz links mit der Suche, die zweite ganz rechts. Beide geben als Resultat die Zahl 7 zurück.
Die Funktionen kombiniert
Die Textfunktionen werden erst brauchbar, wenn man sie kombiniert.
Um den Nachnamen rauszufiltern aus vName, ist ein Left(vName, 6) Blödsinn,
weil der Nachname ja nicht immer 6 Zeichen lang ist. Haben wir aber vorher die
Position des Leerschlages rausgefunden, dann haben wir eine variable Länge:
VBA-Grundlagen
Seite 44 von 74 Version 3.2 / 14.10.2014 © 2014 Daniel Hofer
Dummerweise haben wir so in der Variablen vNachname am Ende noch ein
Leerzeichen, weil vPos um ein Zeichen zu gross ist. Also korrigieren wir das
noch:
vbTextCompare, vbBinaryCompare
Geben wir in der InStr- resp. InStrRev-Funktion vbTextCompare an, dann
unterscheidet VBA Gross- und Kleinschreibung in der Suche nicht.
vbBinaryCompare hingegen beachtet die Gross- und Kleinschreibung.
Datums-Funktionen
Ich zeige im Folgenden nur zwei eher unbekanntere Funktionen, welche in Excel gelegentlich benötigt werden:
WeekdayName
vWochentag = 1
MsgBox WeekdayName(vWochentag)
Bringt entsprechend:
MonthName
vMonat = 3
MsgBox MonthName(vMonat)
Bringt entsprechend:
VBA-Grundlagen
© 2014 Daniel Hofer Version 3.2 / 14.10.2014 Seite 45 von 74
Bei beiden Funktionen muss allenfalls als weitere Parameter wie der erste Tage
der Woche angegeben werden:
Zellen auf Gültigkeit überprüfen
Häufig müssen wir Zellen oder auch Variablen auf ihre Gültigkeit überprüfen. Ich spreche jetzt nicht davon, ob eine Zelle eine Zahl zwischen 10 und 20 enthält, sondern grundsätzlich, ob es eine Zahl ist, oder dummerweise Text (siehe auch das Thema „InputBox sauber abfangen“ auf Seite 39). Oder wir wollen überprüfen, ob in einer Zelle ein korrektes Datum steckt. Warum machen wir das? Ganz einfach: vergessen wir solche Überprüfungen, treten plötzlich Laufzeitfehler auf, weil wir als Beispiel versuchen, die Zahl 2 mit dem Text „Hallo“ zu multiplizieren, was nicht geht.
Is…-Funktionen
VBA hat bereits einige interessante Funktionen zur Überprüfung eingebaut. Die
meisten sind mehr oder weniger selbsterklärend.
IsNumeric
Der Code könnte z.B. so aussehen:
vZahl = 3
If IsNumeric(vZahl) Then
End If
Wir weisen also einer Variablen eine Zahl zu, und danach überprüfen wir, ob
es sich wirklich um eine Zahl handelt. Wenn obige Variable korrekt vorgängig
deklariert wurde:
Dim vZahl As Long
dann können wir ja nur eine Zahl drin speichern. Manchmal kriegen wir aber
auch Text und wir wissen es wirklich nicht (z.B. die beschriebene InputBox-
Problematik, oder bei einem Import aus anderen Quellen). Dann deklarieren
wir die Variable vZahl als Variant (ausnahmsweise!!):
Dim vZahl As Variant
VBA-Grundlagen
Seite 46 von 74 Version 3.2 / 14.10.2014 © 2014 Daniel Hofer
Und danach:
vZahl = "test"
If Not IsNumeric(vZahl) Then
MsgBox "Bitte Zahl eingeben"
End If
Beachte hier das NOT vor der Funktion. Das dreht den Sinn der Funktion quasi
um.
Selbstverständlich funktioniert die Abfrage auch mit einer Zelle in Excel:
If IsNumeric(Range("A1")) Then
resp. korrekter:
If IsNumeric(Range("A1")).Value Then
IsEmpty
Diese Funktion ist mit Vorsicht zu geniessen (siehe Online-Hilfe).
If IsEmpty(vZahl) Then ‚falls Variable nicht
initialisiert
Sie gibt meist nicht die gewünschten Resultate zurück. Besser ist der Einsatz
der Funktion IsNull.
IsNull
If Not IsNull(vZahl) Then ‚falls Variable nicht leer
Auf leere Zeichenfolge prüfen
Häufig müssen wir prüfen, ob in einer Variablen eine leere Zeichenfolge
steckt. Das prüfen wir so:
If vInput = „“ then
IsEmpty, IsNull und „“ sind nicht identisch und liefern jeweils andere
Ergebnisse!
IsDate
Manchmal ist es praktisch, eine Zelle darauf zu überprüfen, ob ein korrektes
Datum drin steckt:
If IsDate(Range("A1").Value) Then
Hier gehts nicht um die Formatierung des Datums, sondern lediglich, ob der
Inhalt der Zelle im Grundsatz ein Datum ist.
Soll ein bestimmtes Datumsformat überprüft werden, geht das so:
If Range("A1").NumberFormat = “tt.mm.jjjj” Then
Vorsicht! Es existieren zwei Eigenschaften:
NumberFormat
VBA-Grundlagen
© 2014 Daniel Hofer Version 3.2 / 14.10.2014 Seite 47 von 74
NumberFormatLocal
Schreiben wir in der Zelle A1 das aktuelle Datum in der Form „28.07.2013“
rein, und geben mit Debug.Print obige Eigenschaften aus, dann schreibt VBA:
NumberFormat= m/d/yyyy
NumberFormatLocal= TT.MM.JJJJ
Also aufgepasst, nach was gesucht wird.
Noch ein Hinweis: geben wir die gleichen Infos in einer als „Standard“
definierten Zelle aus, erscheint:
NumberFormat=General
NumberFormatLocal=Standard
Formulare in Excel
Seite 48 von 74 Version 3.2 / 14.10.2014 © 2014 Daniel Hofer
Formulare in Excel
In VBA können Formulare ähnlich wie in Access erstellt werden. Dies kann als
Beispiel für eine benutzerdefinierte InputBox verwendet werden:
Erstellt werden Formulare als Beispiel über den folgenden Menüpunkt:
Aufruf eines Formulars
Um aus einer Prozedur ein Formular aufzurufen, schreibt man meistens: frmInputbox.Show
Diese Zeile zeigt das Formular an. Vorsicht! Der nachfolgende Code wird normalerweise fortgesetzt. Meistens wollen wir dies jedoch nicht. Wir warten nämlich auf eine Eingabe im Formular, und erst nach dem Schliessen des Formulars soll der Code fortgesetzt werden. Aus diesem Grund macht es Sinn, obige Codezeile anzupassen auf: frmInputbox.Show 1
Diese Zahl 1 hinter dem Show dient dazu, dass das Formular als sog. modales Fenster geöffnet wird. Der gesamte Code einer Testprozedur könnte so aussehen: Sub pDialogTest()
Dim vInput As Single
frmInputbox.Show 1
vInput = frmInputbox.eZahl
Debug.Print vInput
End Sub
Formulare in Excel
© 2014 Daniel Hofer Version 3.2 / 14.10.2014 Seite 49 von 74
Schliessen des Formulars, Variante 1
Dazu können wir als Beispiel einen Button mit dem Namen „cmdOK“ verwenden. Im Ereignis „Beim Klicken“ schreiben wir: Private Sub cmdOK_Click()
frmInputbox.Hide
End Sub
Dieser Code funktioniert zusammen mit der obigen Testprozedur pDialogTest. Das Formular wird nicht wirklich geschlossen, sondern nur unsichtbar gemacht. Wir dürfen es nicht schliessen, weil wir in der Testprozedur pDialogTest auf das Textfeld eZahl im Formular zugreifen.
Schliessen des Formulars, Variante 2
Wir können das Formular auch komplett schliessen, zerstören oder beenden: Private Sub cmdOK_Click()
Unload frmInputbox
End Sub
Jetzt ist das Formular aber nicht mehr vorhanden, d.h. obige Testprozedur pDialogTest funktioniert nicht mehr. Wir greifen dort ja auf ein Formularfeld zu: vInput = frmInputbox.eZahl
Aber dieses existiert zu diesem Zeitpunkt gar nicht mehr. Dementsprechend müssen wir den Code in der Testprozedur auch anpassen.
Parameter-Übergabe mittels globaler Variable
Wollen wir das Formular wirklich mit Unload frmInputbox
beenden, muss die Übergabe der Variablen über globale Variablen geschehen. In der Regel sind globale Variablen unschön, aber dies hier ist eine Ausnahme. Die Testprozedur sieht nun wie folgt aus: Global vInput as Single
Sub pDialogTest()
frmInputbox.Show 1
Debug.Print vInput
End Sub
Jetzt haben wir die Variable vInput oberhalb, d.h. ausserhalb der Prozedur pDialogTest deklariert. Sie ist für jedes Modul (und somit auch für das Formular) sichtbar. Im OK-Button des Formulars schreiben wir nun: Private Sub cmdOK_Click()
vInput = Me.eZahl
Unload frmInputbox
End Sub
Formulare in Excel
Seite 50 von 74 Version 3.2 / 14.10.2014 © 2014 Daniel Hofer
Bevor wir das Formular zerstören, übergeben wir der globalen Variablen vInput den Wert des Textfeldes.
Textfeld nur zur Eingabe von Zahlen definieren
Dazu verwenden wir das Ereignis „Beim Tastendruck“ des Textfeldes: Private Sub eZahl_KeyPress(ByVal KeyAscii As
MSForms.ReturnInteger)
If KeyAscii < 48 Or KeyAscii > 58 Then
KeyAscii = 0
End If
End Sub
Rotes Schliessen-Kreuz ignorieren
Soll ein Klick auf das rote Kreuz oben rechts im Formular verhindert werden, kann dies wie folgt geschehen: Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
Cancel = 1
End Sub
Import aus anderen Quellen
© 2014 Daniel Hofer Version 3.2 / 14.10.2014 Seite 51 von 74
Import aus anderen Quellen
Excel kann mit verschiedenen Techniken auf fremde Daten zugreifen. Im Groben
unterscheiden wir folgende Technologien:
Native-Import (direkter Import) von Daten
Import über DAO
Import über ADO
ODBC
Einfach ausgedrückt sind es verschiedene Produkte, über welche man einen Import
resp. einen Zugriff auf fremde Daten erstellen kann. DAO und ADO wurden beiden
im Hause Microsoft entwickelt. Jahrelang wurde DAO stiefmütterlich behandelt. Seit
der Office Version 2010 gilt DAO offiziell als Zukunftsprodukt, während ADO nicht
mehr weiterentwickelt wird. Aber warten wir mal ab. In einigen Jahren kann sich das
Blatt wieder wenden.
Ich zeige auf den nächsten Seiten folgende Import-Möglichkeiten:
Einlesen einer Textdatei
Zugriff auf eine Access-Datenbank über DAO
Einlesen einer dBase-Tabelle über ADO
Einlesen einer Textdatei
Diese Möglichkeit benötigt keinerlei Treiber oder Programm von Drittherstellern. VBA hat die Möglichkeit direkt eingebaut. Allerdings sind die Möglichkeiten hier sehr rudimentär. Der Code sieht so aus:
In der While-Schlaufe lesen wir Zeile für Zeile ein. In diesem Beispiel geben wir diese Zeile einfach in das Direktfenster aus. In der Praxis würden wir stattdessen
Import aus anderen Quellen
Seite 52 von 74 Version 3.2 / 14.10.2014 © 2014 Daniel Hofer
eine Array-Variable (ein Feld) füllen. Jede Position der Array-Variable enthält eine Zeile. Als zweiten Schritt müssen wir diese Zeile in der Array-Variable in Excel-Zellen abfüllen. Dies kann manuell mittels Text-Funktionen (Left, Right, Mid, Len, InStr) geschehen. Oder wir nehmen den „Text-in-Spalten-Assistenten“ und schauen, was der Makrorekorder aufzeichnet: Selection.TextToColumns Destination:=Range("A1"),
DataType:=xlDelimited, TextQualifier:=xlDoubleQuote,
ConsecutiveDelimiter:=False, Tab:=True,
Semicolon:=False, Comma:=False, Space:=False,
Other:=True, OtherChar:="|", FieldInfo:=Array(Array(1,
1), Array(2, 1), Array(3, 1), Array(4, 1), Array(5, 1),
Array(6, 1)), TrailingMinusNumbers:=True
Excel-Datei öffnen und Daten daraus kopieren
Folgender Code öffnet eine bestimmte Excel-Datei, kopiert den Datenbereich in die Zwischenablage, und fügt diesen in der aktuellen Datei wieder ein:
Dieser Code ist insofern sauber, als dass wir die Excel-Arbeitsmappen gleich sauber in Variablen (objSource und objTarget) speichern. Das ist auch im Kapitel „Excel-Dateien öffnen“ auf Seite 23 beschrieben. Zwei Seiten weiter hinten zeige ich eine Variante, welche ohne diese Zuweisung auskommt. Aber die Version auf dieser Seite hier ist definitiv besser und professioneller. Sollen die kopierten Daten nicht in der aktuellen Datei (wo ja auch der VBA-Code steckt) eingefügt werden, müssen wir zuerst eine neue Arbeitsmappe erstellen und am besten gleich speichern:
Import aus anderen Quellen
© 2014 Daniel Hofer Version 3.2 / 14.10.2014 Seite 53 von 74
Komplexe Datenübername aus mehreren Excel-Dateien
Im Folgenden zeige ich eine komplexere Import-Methode. Wir öffnen innerhalb einer Schleife acht Dateien „Kunden1.xlsx“ bis „Kunden8.xlsx“ und fügen die Daten jeweils zuunterst an der bestehenden Liste an. Eine solche Liste zum Importieren sieht so aus:
Der Trick oder das Problem ist, dass die erste Datei ganz normal mit dem Bereich Range(„A1“).CurrentRegion importiert werden kann. Die weiteren Dateien wollen wir aber erst ab der Zeile 2 importieren. Sonst hätten wir ja jedes Mal die Kopfzeile mit eingefügt; das wollen wir vermeiden.
Import aus anderen Quellen
Seite 54 von 74 Version 3.2 / 14.10.2014 © 2014 Daniel Hofer
Wie vor zwei Seiten erklärt, ist dieser Code zwar in Ordnung, aber nicht ganz sauber. Dies aus dem Grund, weil wir nicht mit Objekt-Variablen wie objSource und objSheet, etc. arbeiten.
Zugriff auf Access mittels DAO
Der Zugriff auf eine Access-DB mittels DAO sieht immer genau gleich aus: Sub pAccessImport()
Dim vDB As DAO.Database
Dim vRS As DAO.Recordset
Dim vFilename As String
Dim i As Integer
i = 2
vFilename = "P:\tn\V8A\Daniel\TopFood.mdb"
Set vDB = OpenDatabase(vFilename)
Set vRS = vDB.OpenRecordset("tblKunden", dbOpenDynaset)
If Not (vRS.BOF And vRS.EOF) Then
vRS.MoveFirst
While Not vRS.EOF
Cells(i, 1) = vRS.Fields("tNachname")
Cells(i, 2) = vRS.Fields("tVorname")
Cells(i, 3) = vRS.Fields("tOrt")
vRS.MoveNext
i = i + 1
Wend
End If
Import aus anderen Quellen
© 2014 Daniel Hofer Version 3.2 / 14.10.2014 Seite 55 von 74
End Sub
Erklärung des Codes
Die gelb markierten Zeilen gehören zum eigentlichen Access-Zugriff. Wir
benötigen ein Database-Objekt, in welchem die MDB-Datei steckt. Dann
benötigen wir ein Recordset-Objekt, welches die Tabelle oder die Abfrage
enthält.
If Not (vRS.BOF And vRS.EOF) Then
Mit dieser Zeile kontrollieren wir, ob überhaupt Daten vorhanden sind. Die
Eigenschaft BOF (Begin of file) ist True, falls der Datensatzzeiger am Beginn der
Tabelle ist. EOF (End of file) ist True, wenn der Datensatzzeiger am Ende der
Tabelle ist. Wenn beides gleichzeitig zutrifft, sind keine Daten vorhanden.
vRS.MoveFirst
Wir wissen nicht genau, wo sich der Datensatzzeiger befindet, also gehen wir
sicherheitshalber an den Anfang.
While Not vRS.EOF
Solange das Ende der Tabelle nicht erreicht ist, machen wir irgendetwas, z.B.
Daten einlesen;-).
vRS.MoveNext
Es ist wichtig, in der Schleife jeweils einen Datensatz weiter zu springen, sonst
landen wir in einer Endlosschleife, was allenfalls unser PC zum Absturz bringen
kann.
Import aus anderen Quellen
Seite 56 von 74 Version 3.2 / 14.10.2014 © 2014 Daniel Hofer
Einlesen einer dBase-Tabelle über ADO
Erklärung des Codes
Die gelben Zeilen sind wieder zwingend nötig für die Verbindung. Anstelle eines
Database-Objekts wie bei DAO haben wir nun ein Connection-Objekt. Aber
sonst ist es ähnlich.
ConnectionString
Die grüne Zeile ist äusserst speziell. In dieser Zeile geben wir den sog.
Connection-String zur Datenbank an. Dies ist meist ein recht komplizierter
Ausdruck, den man sich nicht merken kann. Aus diesen Grund gibt es dafür eine
Homepage3, welche sämtliche Connection-Strings auflistet, welche man in der
Praxis so braucht. Benötigen Sie einen Zugriff auf einen Oracle- oder SQL-
Server? Dann suchen Sie sich einfach den entsprechenden Connection-String
raus.
SELECT * FROM TBLADRES.DBF WHERE tNachname = 'Huber'
Wir können direkt in der Open-Methode des Recordsets die Datenmenge
bereits einschränken. Das macht den Zugriff auf die externen Daten extrem viel
schneller; vorausgesetzt, wir benötigen nur einen Teil der Daten.
Set rsAdressen = Nothing
3 Sie Kapitel „Homepages“ auf Seite 56.
Import aus anderen Quellen
© 2014 Daniel Hofer Version 3.2 / 14.10.2014 Seite 57 von 74
Set dbConnection = Nothing
Diese Zeilen dienen exemplarisch als Hinweis, dass einmal erstellte Objekte
(das erkennen wir am SET-Befehl vor der ersten Zuweisung zu Beginn der
Prozedur) am Ende der Prozedur unbedingt wieder „zerstört“ resp. geschlossen
werden sollten!
Bei kleinen Code-Fragmenten spielt das keine Rolle. Aber bei grösseren
Projekten können wir irgendwann in ein Speicher-Problem geraten, wenn wir
immer neue Objekte erstellen, die alten aber nie beenden.
Bild in Excel einfügen
Der folgende Code fügt ein Bild aus einer Datei in die aktuell selektierte Zelle ein. Damit die Position stimmt, muss das Bild noch korrekt positioniert werden. Dim vPath As String
Dim vFile As String
Dim vPic As Picture
vPath = "P:\Logos\Unterschriften\"
vFile = vPath & „Unterschrift1.png"
Set vPic = ActiveSheet.Pictures.Insert(Filename:=vFile)
vPic.Left = ActiveCell.Left
vPic.Top = ActiveCell.Top
Diverses
Seite 58 von 74 Version 3.2 / 14.10.2014 © 2014 Daniel Hofer
Diverses
Verweise, Early-Binding und Late-Binding
Erstellen wir eine Verbindung zu einer anderen Applikation wie Word oder Powerpoint, oder greifen wir mittels DAO auf eine Access-DB, dann können wir den Zugriff auf diese Fremdapplikation auf zwei Arten definieren:
Early-Binding
Late-Binding
Early-Binding
Early-Binding heisst einfach ausgedrückt, dass wir schon zur Laufzeit eine
Verbindung, hier als Beispiel zu ADO, herstellen. Damit wir dies machen,
müssen wir in den Verweisen den entsprechenden Eintrag setzen:
Besteht diese Verbindung (im unteren Bereich des Fensters sehen wir die
Angabe, um welche DLL-Datei es sich handelt), können wir wie gewohnt in der
Prozedur die Variablen deklarieren:
Dim dbConnection As ADODB.Connection
Dim rsAdressen As ADODB.Recordset
Und weiter unten geschieht die Zuweisung:
Set dbConnection = New ADODB.Connection
Set rsAdressen = New ADODB.Recordset
Late-Binding
Wenden wir Late-Binding an, ist das manuelle Setzen eines Verweises im
Extras-Menü nicht nötig! Dafür sieht die Deklaration der Objekt-Variablen wie
folgt aus:
Dim dbConnection As Object
Dim rsAdressen As Object
Und die Zuweisung der Variablen:
Set dbConnection = CreateObject("ADODB.Connection")
Set rsAdressen = CreateObject("ADODB.Recordset")
Diverses
© 2014 Daniel Hofer Version 3.2 / 14.10.2014 Seite 59 von 74
Was ist nun der Unterschied?
Bei Early-Binding haben wir den Vorteil, dass VBA bereits zur Laufzeit die
Methoden und Eigenschaften der Objektvariablen kennt. D.h. schreiben wir in
unserem Code dbConnection., erscheint das Dropdown-Menü:
Dafür ist der Verweis von Hand manuell gesetzt. Gehen wir mit unserer Makro-
Datei an einen Computer, bei welchem dieser Verweis nicht gesetzt ist, kriegen
wir eine Fehlermeldung.
Beim Late-Binding müssen wir auf obiges Dropdown-Menü verzichten, dafür
muss der Verweis nicht manuell gesetzt sein.
Automation (Steuerung anderer Applikationen)
In VBA können andere Applikationen gesteuert werden. Wir können z.B. innerhalb von Access-VBA Word starten und mit Daten füllen. Wir können aber auch in Word-VBA ein Excel-Sheet öffnen und Daten rausholen. Da funktioniert fast jede Variante.
Aus Excel Word automatisieren
Als Beispiel erstellen wir eine Prozedur, welche ein bestehendes Word-
Dokument öffnet, und dort in der Textmarke „bAdresse“ die Zelle A1 vom
aktuellen Sheet einfügt.
Der Code dazu sieht etwa so aus:
Sub pWordBrief()
Dim objWord As Word.Application
Dim objDoc As Word.Document
Dim rng As Word.Range
Set objWord = CreateObject("Word.Application")
Set objDoc =
objWord.Documents.Open(Filename:="d:\Testdokument.doc
")
Set rng = objDoc.Bookmarks("bAdresse").Range
rng.Text = Range("A1")
objWord.Visible = True
Set objWord = Nothing
End Sub
Diverses
Seite 60 von 74 Version 3.2 / 14.10.2014 © 2014 Daniel Hofer
Der Aufruf geschieht mit Early Binding, d.h. der Verweis zur Microsoft Word
Library muss vorgängig gesetzt sein! (siehe Abschnitt Early-Binding auf Seite 58)
Wir sehen, dass ein Range-Objekt in Word einfach einen Textbereich
widespiegelt, während in Excel das Range-Objekt ein Zellbereich ist.
Fehler und Fehler und Fehler…
Obiger Code muss allerdings noch sehr viel verbessert werden, da bei der
Automation unmögliche Fehler auftauchen können.
Z.B. macht es Sinn, die Existenz der Textmarke zu prüfen:
If objDoc.Bookmarks.exists("bAdresse") = True Then
Weiter sollte überprüft werden, ob der Verweis zur Microsoft Word Library
überhaupt existiert. Dies ist komplizierter und kann mit VBA nur gemacht
werden, wenn in den Sicherheitseinstellungen von Excel die Option auch aktiv
ist:
Hier ist es unter Umständen einfacher, nun wirklich mit der Fehlerbehandlung
zu tricksen. Dummerweise kann in diesem Fall Early Binding nicht verwendet
werden. Hier prüft schon der Editor vor dem Kompilieren, ob die Library
sauber verlinkt ist. Es ändert sich einerseits die Variablendeklaration:
Dim objWord As Object
Dim objDoc As Object
Dim rng As Object
Bevor nun die Instanzierung von objWord geschieht, kommt die Fehler-
Ignorierung:
On Error Resume Next
Set objWord = CreateObject("Word.Application")
If Err > 0 Then
MsgBox "Das war nix mit Word"
Exit Sub
End If
Somit wird zwar nicht, wie oben erwähnt, der Verweis auf die Library
getestet, sondern einfach, ob der Zugriff auf Word möglich ist.
Diverses
© 2014 Daniel Hofer Version 3.2 / 14.10.2014 Seite 61 von 74
Fazit zur Automation:
Die Entwicklung von Code zur Automation braucht sehr viel Gedult und z.T.
tagelanges Testen und Suchen nach Lösungen in Büchern oder im Internet, da
es sehr Fehler-anfällig ist.
Aktuelle Datei als Email versenden
Sub pEmailVersand()
Dim vDatei As String
Dim objOutloook As Object
Dim objMail As Object
vDatei = ThisWorkbook.FullName
Set objOutlook = CreateObject("Outlook.Application")
Set objMail = objOutlook.CreateItem(0)
With objMail
.To = "[email protected]"
.Subject = "Betreff"
.Body = "Die Nachricht"
.Attachments.Add vDatei 'Anhängen der aktuellen Datei
.Display 'Email nicht senden, sondern öffnen
'.Send 'Oder Email ungefragt senden
End With
End Sub
Tabellenfunktionen
Eingebaute Tabellenfunktionen aufrufen
Eingebaute Tabellenfunktionen können wie folgt aufgerufen werden:
Flaeche = Application.WorksheetFunction.Acos(x)
Eine eigene Tabellenfunktion erstellen
Dazu benötigen wir ein Modul. Es handelt sich dabei um eine ganz normale
Funktion:
Function Flaeche(x As Single) As Single
Flaeche = Application.WorksheetFunction.Acos(x)
End Function
In der Tabelle erscheint dann diese neu erstellte Funktion sofort:
Diverses
Seite 62 von 74 Version 3.2 / 14.10.2014 © 2014 Daniel Hofer
Einer selbst erstellten Excel-Funktion einen Hilfetext hinzufügen
(muss nur 1x gemacht werden)
Applications.MacroOptions macro:=“fKreisflaeche“,
Description:=“Na aber hallo, das kennste doch!“
Zugriff auf das System
Registry bearbeiten
Irgendeine Variable (hier „vNachname“) in der Registry speichern
SaveSetting appname:="Digicomp", section:="Kurs E7V",
Key:="Nachname", setting:=vNachname
Speicherpfad:
\\HKCU\Software\VB and VBA Program Settings\..
Wert „Nachname“ aus der Registry holen
Optimierung: gesuchter Wert als Parameter der Funktion fLoadSettings
definieren
Function fLoadSettings() As String
fLoadSettings = GetSetting(appname:="Digicomp",
section:="Kurs E7V", Key:="Nachname")
End Function
Aktuellen Benutzer erfahren
vPfad = Environ(“USERNAME”)
So können sämtliche Umgebungsvariablen erfragt werden, welche in der
Eingabeaufforderung mittels SET erscheinen.
Einstellungen VBA-Editor
Es gibt einige Einstellungen im VBA-Editor, die für die tägliche Arbeit Sinn machen.
Option Explicit
Der Ausdruck "Option Explicit" zu Beginn eines Moduls dient dazu, dass
sämtliche Variablen vor dem ersten Gebrauch sauber deklariert werden
müssen, d.h. wir müssen zuerst schreiben:
Dim intZahl as integer
bevor wir schreiben können:
intZahl = inputbox(….)
Diverses
© 2014 Daniel Hofer Version 3.2 / 14.10.2014 Seite 63 von 74
Damit wir nicht vergessen, bei jedem Modul immer "Option Explicit"
anzugeben, können wir in den Optionen des VBA-Editors dies als Voreinstellung
definieren. Hierzu gehen wir auf "Extras/Optionen":
Symbolleiste sinnvoll ergänzen
In der Regel fehlen in der Symbolleiste die Symbole für das Auskommentieren
sowie das "Einzug vergrössern" und Verkleinern von Zeilen.
Finden tun wir diese Symbole unter "Ansicht/Symbolleisten/Anpassen":
Die vier gelb markierten Symbole können wir nach oben in die Symbolleiste
nehmen.
Einzug vergrössern und Verkleinern
Kleiner Tipp: mehrere Zeilen um eine Tabposition nach rechts verschieben geht
nicht nur mit den obigen Symbolen, sondern auch durch das einfache Drücken
der Tabulator-Taste. Den Einzug wieder verkleinern erreichen wir durch
Drücken von
Shift + Tabulator.
Diverses
Seite 64 von 74 Version 3.2 / 14.10.2014 © 2014 Daniel Hofer
Scripting Runtime (2007)
Da in Excel 2007 die FileSearch-Methode im Application-Objekt fehlt, müssen
wir mit der Scripting Runtime arbeiten (Windows Scripting Host).
Dazu wählen wir im VBA-Editor den Menüpunkt "Extras / Verweise…" aus. Im
erscheinenden Dialog wählen wir folgenden Punkt aus:
Makros
Icon in der Schnellzugriffsleiste
Das Icon ist nur für den aktuellen Benutzer sichtbar! Wird eine Arbeitsmappe
mit Makros weitergegeben, sind die Makros zwar enthalten, die Icons fehlen
allerdings
Diverses
© 2014 Daniel Hofer Version 3.2 / 14.10.2014 Seite 65 von 74
Zugriff auf Funktionen in Add-In Dateien
Wir sprechen hier nicht von DLL-Dateien, sondern von XLA- resp.XLAM-Dateien.
Zum Erstellen einer solchen Add-In-Datei öffnen wir Excel ganz leer und gehen
in den VBA-Editor. Dort fügen wir ein Modul ein.
Als Beispiel erfassen wir folgende Excel-Funktion:
Nun speichern wir die Datei unter „dhFunctions.xlam“. Ich wähle jeweils die
Kurzzeichen dh vorab, damit ich weiss, dass das Add-In von mir stammt.
Entsprechend kann dies angepasst werden.
Der Standard-Pfad für Add-In-Dateien lautet:
C:\Users\[Username]\AppData\Roaming\Microsoft\AddIns
Achtung! Damit das Add-In funktioniert, muss es im Add-In-Manager noch
aktiviert warden:
Diverses
Seite 66 von 74 Version 3.2 / 14.10.2014 © 2014 Daniel Hofer
Dieses Fenster lässt sich in den Optionen finden:
Alternativer Speicherpfad
Die XLAM-Datei kann auch in den XLSTART-Ordner gelegt werden. Diese
Version ist sogar besser als obige, weil das Addin dann sofort aktiv ist ohne
jegliche Aktivierung.
Homepages zu Excel
© 2014 Daniel Hofer Version 3.2 / 14.10.2014 Seite 67 von 74
Homepages zu Excel
Allgemein zu Office und VBA
www.officehilfe.ch Meine eigene Seite mit Tipps & Tricks zu Office.
Diese Seite lebt! Schreiben Sie mir ein Email mit
Themen, die Sie interessieren. Dann werde ich
einen Beitrag dazu schreiben.
www.office-loesung.de Extrem umfangreiches Diskussionsforum
www.held-office.de FAQ's und Tipps von Bernd
www.schmittis-page.de Tipps von Marcus
www.connectionstrings.com Eine grosse Auswahl an Connections-Strings, um
eine Verbindung auf fremde Datenquellen mittels
ADO resp. ODBC zu erstellen.
www.vb-tec.de Häufige VB-Probleme erläutert, kurz und bündig
(deutsch)
www.vbarchiv.net Sehr umfangreiche VB-Seite auf deutsch
Excel
www.xlam.ch Limitationen in Excel, extrem umfangreiche Seiten
www.herber.de Äusserst umfangreiche VBA-Seite speziell für Excel
www.hajo-excel.de Seite von Hajo mit vielen Infos
www.excelformeln.de Kein VBA, aber dafür ausführliche Infos zu
komplexen Formeln (meist Matrix-Funktionen)
excelabc.de Berti's Tipps & Tricks
www.xl-faq.de FAQ-Seite von Frank
www.online-excel.de Diverse Tipps zu VBA
Homepages zu Access
www.donkarl.com Wohl die beste FAQ-Seite für Access auf deutsch
www.access-im-
unternehmen.de
Profi-Tipps. Die vollständigen Artikel sind nur nach
Kauf einer Zeitschrift verfügbar (lohnt sich aber für
Access-Leute)
www.access-tutorial.de Allgemeine (aber sehr gute) Access-Seite, nicht VBA
Ribbons
Seite 68 von 74 Version 3.2 / 14.10.2014 © 2014 Daniel Hofer
Ribbons
Geniales Ribbon-Blog http://www.excelguru.ca/blog/2006/
12/01/ribbon-example-table-of-
contents/
MSDN-Welcome Seite über
Ribbons
http://msdn2.microsoft.com/en-
us/office/aa905530.aspx
Offizielle MSDN-Seite über
Ribbons, Teil 1
http://msdn2.microsoft.com/en-
us/library/aa338202.aspx
Custom UI Editor Tool
Ganz schlichtes Tool, in
welchem eine Excel-Datei
geöffnet werden kann.
Danach ein Beispiel-Ribbon
laden aus dem Menü
„Sample“ und anpassen. Am
Schluss wieder speichern
http://openxmldeveloper.org
resp.
http://openxmldeveloper.org/blog/b
/openxmldeveloper/archive/2010/08/
10/23248.aspx
Ribbon Customizer
Kann die originalen Ribbons
auch anpassen!
http://pschmid.net/office2007/ribb
oncustomizer/index.php
Bilder der Icons können
folgendermassen gefunden
werden:
Im Anpassen-Dialog der
Einstellungen mit der Maus
auf einen Befehl fahren und
schauen, was er im Tooltip
schreibt
Infos zu 2010 Updates http://www.rondebruin.nl/ribbon.ht
m
Grundsätzliches zu Ribbons
Unter Office 2007 kann die Multifunktionsleiste mittels VBA überhaupt nicht angepasst werden Unter 2010 ist dies wieder möglich. Trotzdem macht es auch unter 2010 und 2013 häufig Sinn, nach der „alten“ Methode von 2007 vorzugehen.
Ribbons
© 2014 Daniel Hofer Version 3.2 / 14.10.2014 Seite 69 von 74
Meistens will man das Menüband (wie es seit 2010 heisst) nicht grundsätzlich ändern, sondern nur für eine bestimmte Excel-Mappe. Und deshalb passt man am besten diese Datei an, indem man mittels XML die Anpassungen vornimmt (siehe nächster Abschnitt).
Geeignete Datei-Formate
Grundsätzlich muss es ein Dateiformat sein, das Makros speichern kann (sonst
ist die Anpassung der Ribbons ja sinnlos, v.a. wenn man eigene Knöpfe
einfügen will). Soll das angepasste Ribbon für mehrere Dateien gelten, dann
nimmt man am besten das Add-In-Format XLAM (diese Mappe wird dann im
Hintergrund und unsichtbar geöffnet).
Kurze Anleitung für die Anpassung des Ribbons unter Office 2007/2010
Als erstes müssen wir den CustomUI Editor (Link oben) runterladen und installieren. Das ergibt ein Icon auf dem Desktop:
Jetzt kann im CustomUI Editor die entsprechende Word- oder Excel-Datei geöffnet werden. Achtung, es muss sich um eine Datei mit Makros handeln, d.h. mit einem „m“ in der Endung, also docm oder xlsm als Beispiel. Nun sollte das etwa so aussehen:
Jetzt können wir unter „Insert“ gehen.:
Ribbons
Seite 70 von 74 Version 3.2 / 14.10.2014 © 2014 Daniel Hofer
Je nach Version wählen wir 2007 oder 2010 aus. Danach sollte das Bild etwa so aussehen:
Jetzt klicken wir wieder auf „Insert“ und wählen ein Beispielcode aus:
Danach erscheint im rechten Fenster der entsprechende XML-Code:
Es macht Sinn, das Fenster breit genug zu machen, damit der Code auch sinnvoll formatiert erscheint. Hier können nun die entsprechenden Änderungen vorgenommen werden (viel Spass)
Ribbons
© 2014 Daniel Hofer Version 3.2 / 14.10.2014 Seite 71 von 74
Am Schluss speichern wir die Datei und öffnen die Excel-Datei in Excel. Es sollte nun ein neues Register „Contoso“ erscheinen:
Nun folgt noch der letzte Schritt. Wir müssen nämlich auf den Klick der Buttons ganz rechts reagieren. Wie wir oben im XML-Code sehen, steht dort unter OnAction als Beispiel die Ereignisprozedur „conBoldSub“. Also fügen wir diese Prozedur in einem Modul in unserer Excel-Datei ein:
Und schon erscheint obige Messagebox, wenn wir auf den Button „ConBold“ klicken.
Datentypen
Seite 72 von 74 Version 3.2 / 14.10.2014 © 2014 Daniel Hofer
Datentypen
Ganzzahl 1 Byte 0 bis 255
Wahrheitswert 2 Bytes True oder False
Ganzzahl 2 Bytes -32‘768 bis 32‘768
Ganzzahl
4 Bytes -2‘147‘483‘648 bis
2‘147‘483‘647
Gleitkommazahl einfacher
Genauigkeit
4 Bytes Fliesskommazahl mit 8 Stellen
Genauigkeit
Gleitkommazahl doppelter
Genauigkeit
8 Bytes Fliesskommazahl mit 16 Stellen
Genauigkeit
Skalierte Ganzzahl 8 Bytes Festkommazahlen mit 15 Stellen
vor und 4 Stellen nach dem
Komma
Skalierte Ganzzahl
14 Bytes Untertyp von Variant.
Genauigkeit 28 Stellen (Anzahl
Stellen vor dem Komma müssen
abgezogen werden)
Datum 8 Bytes
Variable Länge 10 Bytes plus Länge Grösse nur durch RAM
beschränkt
Feste Länge Länge Bis ca. 65‘400 Zeichen
(Zahlen) 16 Bytes Gross und langsam!
(Text) 22 Bytes plus Länge
4 Bytes
© 2014 Daniel Hofer Version 3.2 / 14.10.2014 Seite 73 von 74
Index
Access und DAO ............................... 54 ActiveCell ......................................... 11 ActiveSheet ...................................... 12 ActiveWorkbook.Save ...................... 14 Add-In .................................... 9, 65, 69 Aktuellen Benutzer erfahren ............ 62 Andere Reihenfolge der Parameter .. 30 Anzeigen eines Speichern-Dialogs .... 22 Application.InputBox ........................ 40 Application.ScreenUpdating ............. 16 Arrays ............................................... 31 Auf leere Zeichenfolge prüfen .......... 46 Autofilter .......................................... 13 Automation ...................................... 59 Bild in Excel einfügen ....................... 57
........................................... 72 ByRef ................................................ 27
................................................. 72 Cells(20, 1) ....................................... 11 ColorIndex ........................................ 11 Dateiendungen................................... 9 Datentypen ...................................... 72 Datumsformat .................................. 47 dBase ............................................... 56 Dialoge selber gemacht .................... 48 Do Loop ............................................ 35 Early-Binding .................................... 58 Einlesen einer Textdatei ................... 51 Einstellungen VBA-Editor ................. 62 Enumerationen ................................ 28 Excel importieren ............................. 52 Excel-Dateien öffnen ........................ 23 Fehler-Behandlung ........................... 37 Felder ............................................... 31 For Next ........................................... 35 Formulare in Excel ............................ 48 Funktionen ....................................... 29 Geeignete Datei-Formate für eine
Ribbon-Anpassung ........................ 69
Gleichzeitig mehrere Excel-Dateien offen ............................................. 17
Gross- und Kleinschreibung .............. 44 Gültigkeitsbereiche .......................... 30 Homepages ...................................... 67 IF 17 Import .............................................. 51
Access ........................................... 54 Bild ................................................ 57 dBase ............................................ 56 Excel .............................................. 52 Textdatei ....................................... 51
Inhalt .................................................. 7 Inputbox ........................................... 18 InputBox sauber abfangen ............... 39 InStr ................................................. 43 InStrRev ............................................ 43 Is…-Funktionen ................................. 45 IsDate ............................................... 46 IsEmpty ............................................ 46 IsNull ................................................ 46 IsNumeric ......................................... 45 IsNumeric() ....................................... 39 Konstanten ....................................... 29 LAENGE ............................................ 42 Late-Binding ..................................... 58 Left ................................................... 43 Len ................................................... 43 Limitationen ....................................... 9 LINKS ................................................ 42 Makrorekorder ................................. 18 Mid ................................................... 43 Monatsname .................................... 44 MonthName ..................................... 44 MsgBox ............................................ 33 MsgBox als Funktion ........................ 34 MsgBox als Prozedur ........................ 33 Nachträgliche Korrekturen nach dem
Aufzeichnen .................................. 20 Namen des aktuellen Sheets ändern 22
Index
Seite 74 von 74 Version 3.2 / 14.10.2014 © 2014 Daniel Hofer
Neue Excel-Mappe erstellen ............ 25 Neues Tabellenblatt hinzufügen ...... 22 NOT .................................................. 46 NumberFormat ................................ 47 NumberFormatLocal ........................ 47 Öffnen-Dialog anzeigen .................... 24 On Error ........................................... 37 On Error goto 0 ................................ 38 On Error resume next ....................... 38 Option Explicit .................................. 62 Performance-Vergleich .................... 16 PERSONAL.XLSB ................................. 9 Range statt Cells ............................... 36 Range("A1") ..................................... 11 RECHTS ............................................ 42 Registry bearbeiten .......................... 62 Ribbons ............................................ 68 Right................................................. 43 Schleifen .......................................... 35 Schnellzugriffsleiste ......................... 64 Scripting Runtime ............................. 64 SELECT CASE ..................................... 17 Selection .......................................... 12 SET ................................................... 62 Sinnvolle Einsatzmöglichkeiten des
Rekorders ...................................... 18 Speichern der aktuellen Datei .......... 23 Speichern-Dialogs ............................ 22 Spezielle Zellen ................................ 14 Sprung zur letzten Zelle .................... 14 Standard-Fehlerbehandlung ............ 37
............................................... 72 Suchen und Finden im Range-Objekt 13 Summenformel in VBA ..................... 13
System-Zugriff .................................. 62 Tabellenfunktionen .......................... 61 TEIL .................................................. 42 Teil einer Zelle farbig markieren ....... 12 Text farbig markieren ....................... 12 Textdatei importieren ...................... 51 Text-Funktionen ............................... 42 Trim.................................................. 43 Unsinniger Einsatz des Rekorders .... 18 Variablen .......................................... 26 Variant ............................ 18, 28, 45, 72 vb… .................................................. 34 VBA-Editor ....................................... 62 vbBinaryCompare............................. 44 vbCritical .......................................... 33 vb-Konstanten .................................. 34 vbTextCompare ................................ 44 vbYesNo ........................................... 33 WeekdayName ................................. 44 While Wend ..................................... 35 WITH ................................................ 32 Wochentag ....................................... 44 Word automatisieren ....................... 59 Workbooks.Add ............................... 25 Worksheets löschen ......................... 22 Worksheets(„Tabelle1“) ................... 11 Worksheets.Add ............................... 22 XLAM ................................................ 69 XLSB ................................................... 9 Zellen auf Gültigkeit überprüfen ...... 45 Zugriff auf Access mittels DAO ......... 54 Zugriff auf das System ...................... 62 Zugriff auf Zellen und Bereiche ........ 11