Datenschutzerklärung


Direktnachricht



Ihre Software
Details
Excel/VBA 🔍
Add-Ins

Suche in Beispielen und Tipps zu Excel und VBA

Suchbegriff(e) mit Leerzeichen getrennt:

Assoziative Arrays in VBAMakro/Sub/ProzedurUDF - benutzerdefinierte FunktionArrayfunktion/MatrixfunktionTipp

Kategorie: Arrays ▸ Assoziativ

(Tipp 573) Nachricht zum Beitrag an Autor Nach oben

Kann man in Excel auch mit assoziativen Arrays arbeiten?

In PHP kann man sehr übersichtlich mit assoziativen Arrays arbeiten, wie zum Beispiel

$MeinArray['Vorname'] = 'Manfred';

In Excel geht das auch:

Setzen Sie im VBA-Editor unter Extras ▸ Verweise ein Häkchen vor Microsoft Scripting Runtime oder verwenden Sie Late Binding wie in den folgenden Beispielen. Nun können Sie wie folgt mit assoziativen Arrays arbeiten:

Basis ist das Dictionary oder die Collection. Dabei spielen immer Paare eine Rolle: Key=Item, also ein Schlüsselname und der Eintrag dazu. In den folgenden Beispielen wird der Einfachheit halber (und weil Collection ein paar Nachteile hat) nur das Dictionary verwendet.

Im Code sind hier die einzelnen Inhalte (Keys, Items) zum besseren Verständnis hardcodiert, also fest eingetragen. An dieser Stelle können natürlich auch Variablen oder Zellen verwendet werden, zum Beispiel Spalten- oder Zeilenüberschriften und Zellen mit Daten.

Eine Ebene

Im Beispiel sind die Key=Item-Paare auf einer Ebene. Das heißt, es darf auch keine zwei gleichnamigen Keys geben, sonst wird eine Fehlermeldung ausgegeben.

Sub AssozArray_Einfach() Dim dict, varKey, varKeys, varItems Dim intI As Integer Set dict = CreateObject("Scripting.Dictionary") dict.Add "name", "Müller" dict.Add "vorname", "Johann" dict.Add "wohnort", "Berlin" MsgBox dict("vorname") & " " & dict("name") & " wohnt in " & vbNewLine & dict("wohnort") & "." 'For Each varKey In dict.keys ' MsgBox varKey & vbNewLine & dict(varKey) 'Next varKeys = dict.Keys varItems = dict.Items For intI = 0 To dict.Count - 1 MsgBox varKeys(intI) & ": " & vbNewLine & varItems(intI) Next Set dict = Nothing End Sub

Die MsgBox zeigt, wie die Syntax Dictionary(Key) verwendet werden kann, um auf die einzelnen Elemente zuzugreifen. Darunter sind zwei Schleifen. Mit ihnen wird demonstriert, wie alle Elemente des Dictionarys ausgegeben werden können.


Verschachtelungen, mehrere Ebenen

Elemente von Arrays können wiederum Arrays sein. Dies geht auch bei den assoziativen Arrays bzw. Dictionarys in VBA - auch hier kann verschachtelt werden. Dabei trifft genau das Prinzip der Paare zu, nur dass an der Stelle des Items eine weitere Sammlung (Dictionary oder Collection) ist. Hier wird ein temporäres Dictionary verwendet, das vor jeder Verschachtelung neu erzeugt und danach wieder auf Nothing gesetzt wird. Vorbelegen oder Überschreiben der Items in den einzelnen Schritten funktioniert nicht, da sonst nur auf die letzten Einträge referenziert wird.

Wir wollen im Beispiel ein Dictionary aus sechs Personen erzeugen, das sind also sechs verschiedene Keys. Diesen sechs Personen können nun Details (Nachname, Vorname, Wohnort) zugeordnet werden, müssen aber nicht. So kann der Platz für eine Person auch nur reserviert sein, ohne dass Details enthalten sind.

Die Personen insgesamt sind die Einträge in dicPersonen mit den Keys Person x. Werden Details zugeordnet, erfolgt das Speichern zunächst im temporären Dictionary dictDetails, das dann als Item der Person zugeordnet wird. Gibt es keine Details, wird als Item einfach ein String verwendet.

Sub AssozArray_Levels() Dim dicPersonen, dictDetails, varKey, varKey1 Dim strAusg As String Set dicPersonen = CreateObject("Scripting.Dictionary") Set dictDetails = CreateObject("Scripting.Dictionary") dictDetails.Add "nachname", "Müller" dictDetails.Add "vorname", "Klaus" dictDetails.Add "wohnort", "Berlin" dicPersonen.Add "Person 1", dictDetails Set dictDetails = Nothing Set dictDetails = CreateObject("Scripting.Dictionary") dictDetails.Add "nachname", "Beispielfrau" dictDetails.Add "vorname", "Bärbel" dictDetails.Add "wohnort", "Hamburg" dicPersonen.Add "Person 2", dictDetails Set dictDetails = Nothing Set dictDetails = CreateObject("Scripting.Dictionary") dictDetails.Add "nachname", "Mustermann" dictDetails.Add "vorname", "Franz" dictDetails.Add "wohnort", "Leipzig" dicPersonen.Add "Person 3", dictDetails Set dictDetails = Nothing dicPersonen.Add "Person 4", "Nicht vergeben." Set dictDetails = CreateObject("Scripting.Dictionary") dictDetails.Add "nachname", "Sonne" dictDetails.Add "vorname", "Klara" dictDetails.Add "wohnort", "München" dicPersonen.Add "Person 5", dictDetails Set dictDetails = Nothing dicPersonen.Add "Person 6", "Auch nicht vergeben." MsgBox "Testausgabe: " & vbNewLine & dicPersonen("Person 1")("wohnort") & vbNewLine & dicPersonen("Person 2")("wohnort") strAusg = "" For Each varKey In dicPersonen.keys strAusg = strAusg & vbNewLine & "Person: " & varKey & vbNewLine On Error Resume Next For Each varKey1 In dicPersonen(varKey).keys strAusg = strAusg & "key: " & varKey1 & vbTab & "item: " & dicPersonen(varKey)(varKey1) & vbNewLine Next If Err.Number = 92 Then strAusg = strAusg & vbTab & vbTab & "item: " & dicPersonen(varKey) & vbNewLine Err.Clear End If Next MsgBox strAusg Set dicPersonen = Nothing End Sub

In der MsgBox mit der Testausgabe ist zu sehen, wie die Items ausgegeben werden können. Wir haben hier also nicht nur den Key einer Ebene, sondern hier wird mit Klammerpaaren bis zur unteren Ebene gearbeitet.

Schwieriger ist es mit der kompletten Ausgabe per Schleife. Hätten wir konsequent bei jeder Person eine Verschachtelung mit den Details, würde so etwas reichen:

For Each varKey In dicPersonen.keys strAusg = strAusg & vbNewLine & "Person: " & varKey & vbNewLine For Each varKey1 In dicPersonen(varKey).keys strAusg = strAusg & "key: " & varKey1 & vbTab & "item: " & dicPersonen(varKey)(varKey1) & vbNewLine Next Next

Da aber zwischendurch unverschachtelte Items direkt auf der ersten Ebene sind (Person 4 + 6), käme es hier zu einer Fehlermeldung, dem Fehler 92. Der wird abgefangen und separat behandelt; hier wird der Eintrag direkt ausgegeben. Der Schlüssel, also der Key, ist hier ja die oberste Ebene, die Person selbst.


Dynamische Arrayformel

Zum Verdeutlichen wird hier die zweite Variante als Array ausgegeben, so dass sie als Formel in einer Zelle verwendet werden kann (funktioniert ab Excel 365).

In die Zelle kann einfach =AssozArray_Array() eingegeben werden; als Ergebnis müssten die Key-Item-Paare zu jeder Person erscheinen.

Zum praktischen Einsatz ist dies sicher eher weniger geeignet, da dann eine andere Datenstruktur erforderlich wäre. Sollte das gebraucht werden, lässt sich aber der Array, der erstellt wird, einfach anpassen.

Function AssozArray_Array() Dim dicPersonen, dictDetails, varKey, varKey1 Dim strAusg As String Dim arrRet(1 To 14, 1 To 3), lngRet As LongPtr, intS As Integer Set dicPersonen = CreateObject("Scripting.Dictionary") Set dictDetails = CreateObject("Scripting.Dictionary") dictDetails.Add "nachname", "Müller" dictDetails.Add "vorname", "Klaus" dictDetails.Add "wohnort", "Berlin" dicPersonen.Add "Person 1", dictDetails Set dictDetails = Nothing Set dictDetails = CreateObject("Scripting.Dictionary") dictDetails.Add "nachname", "Beispielfrau" dictDetails.Add "vorname", "Bärbel" dictDetails.Add "wohnort", "Hamburg" dicPersonen.Add "Person 2", dictDetails Set dictDetails = Nothing Set dictDetails = CreateObject("Scripting.Dictionary") dictDetails.Add "nachname", "Mustermann" dictDetails.Add "vorname", "Franz" dictDetails.Add "wohnort", "Leipzig" dicPersonen.Add "Person 3", dictDetails Set dictDetails = Nothing dicPersonen.Add "Person 4", "Nicht vergeben." Set dictDetails = CreateObject("Scripting.Dictionary") dictDetails.Add "nachname", "Sonne" dictDetails.Add "vorname", "Klara" dictDetails.Add "wohnort", "München" dicPersonen.Add "Person 5", dictDetails Set dictDetails = Nothing dicPersonen.Add "Person 6", "Auch nicht vergeben." lngRet = 0 For Each varKey In dicPersonen.keys On Error Resume Next For Each varKey1 In dicPersonen(varKey).keys If varKey1 <> "" Then lngRet = lngRet + 1 arrRet(lngRet, 1) = varKey arrRet(lngRet, 2) = varKey1 arrRet(lngRet, 3) = dicPersonen(varKey)(varKey1) End If Next If Err.Number = 92 Then If dicPersonen(varKey) <> "" Then lngRet = lngRet + 1 arrRet(lngRet, 1) = varKey arrRet(lngRet, 2) = "" arrRet(lngRet, 3) = dicPersonen(varKey) End If Err.Clear End If Next Set dicPersonen = Nothing AssozArray_Array = arrRet End Function

Website-Tipp

Hier gibt es gute Erklärungen von Paul Kelly (englisch): Excel VBA Dictionary – A Complete Guide

BeispieleMakro/Sub/ProzedurTipp

Kategorie: Basics ▸ OOP

(Tipp 219) Nachricht zum Beitrag an Autor Nach oben

Zuerst drehen wir in der aktiven Mappe auf dem Blatt Tabelle1 den Text:

Worksheets("Tabelle1").Rows("1:1").Orientation = 90

Dann drehen wir in der xyz.xls, die natürlich offen sein muss, den Text:

Workbooks("xyz.xls").Worksheets("Tabelle1").Rows("1:1").Orientation = 90

Und jetzt weisen wir an, dass A1 von der Tabelle1 der aktiven Mappe in die xyz.xls in die Tabelle2 in A1 kopiert werden soll (in einer Zeile):

Sheets("Tabelle1").Range("A1").Copy _ Workbooks("xyz.xls").Worksheets("Tabelle2").Range("A1")

Das geht alles ohne Select und Activate.

Besonderheit bei den EigenschaftenTipp

Kategorie: Basics ▸ OOP

(Tipp 218) Nachricht zum Beitrag an Autor Nach oben

Der Punkt spielt bei Objekten immer eine zentrale Rolle. Bei den Eigenschaften kommt noch das Gleichheitszeichen hinzu.

Man nennt das Objekt, danach hinter einem Punkt die Eigenschaft und dann nach einem Gleichheitszeichen, wie die Eigenschaft sein soll.

Beispiel:

Auto.Farbe = Rot

Dies gilt in VBA sowohl für Abfragen als auch für Zuweisungen. Man kann also mit dieser Syntax abfragen, ob ein Auto rot ist; man kann aber auch dem Objekt Auto die Farbe Rot zuweisen. Wenn man von anderen Sprachen, wie zum Beispiel JavaScript oder PHP kommt, muss man dies besonders beachten.

Daten per POST an PHP-Script, Response empfangenMakro/Sub/Prozedur

Kategorie: Netz ▸ Serverkommunikation

(Tipp 594) Beispieldatei Nachricht zum Beitrag an Autor Nach oben

Kommunikation mit PHP
Wie kann ich Daten an ein PHP-Script senden oder Daten von dort empfangen?

Dazu gibt es verschiedene Möglichkeiten. Manche haben Nachteile, zum Beispiel Probleme mit UTF-8 oder dass gesendete Daten in den Server-Logs erscheinen.

Empfehlenswert ist das MSXML2.XMLHTTP-Objekt, mit dem per POST Formulardaten ganz einfach gesendet und Antworten empfangen werden können. Die Daten werden einfach als key=value-Kombinationen an die Adresse des Server-Scripts (Beispiel: PHP) übergeben. Ein einfaches Beispiel dazu:

Sub Post_mit_Response() Dim strURL As String, strPostDaten As String strURL = "https://example.org/phptest.php" strPostDaten = "" strPostDaten = strPostDaten & "name=Müller" strPostDaten = strPostDaten & "&vorname=Hans" strPostDaten = strPostDaten & "&strasse=Blumenweg 22" strPostDaten = strPostDaten & "&ort=Musterort" With CreateObject("MSXML2.XMLHTTP") .Open "POST", strURL, False .setRequestHeader "Content-Type", "application/x-www-form-urlencoded" .Send (strPostDaten) If .ResponseText <> "" Then 'Response je nach Anforderung prüfen MsgBox .ResponseText 'Antwort des Servers ausgeben Else MsgBox "Schiefgegangen.", vbOKOnly + vbCritical, "Fehler" End If End With End Sub

Ein Beispiel für ein zugehöriges PHP-Script:

$adresse = "Die Adresse ist:\n\n"; $adresse .= $_POST['vorname'] . " " . $_POST['name'] . "\n"; $adresse .= $_POST['strasse'] . "\n"; $adresse .= $_POST['plz'] . " " . $_POST['ort'] . "\n"; echo $adresse;

In diesem Beispiel würde PHP aus den einzelnen Angaben eine formatierte Adresse gestalten und diese an VBA senden.

Dadurch können u. a. Daten aus Zellen oder Userformen ganz einfach per Mausklick, Tastendruck oder auch per Event an ein Script auf dem Server gesendet werden, das dann die weitere Verarbeitung erledigt. Somit können Mails versendet oder Eintragungen in Datenbanken (z. B. mySQL) vorgenommen werden usw.

Die Antwort des Servers ist hier natürlich nur reiner Text. Für komplexere Vorgänge sollten Sie sich ansehen, was in der Zusammenarbeit von VBA mit JSON möglich ist.

Download: excel_php_json.xlsm

Lauftext per Timer

Kategorie: Add-In ▸ Userform

(Tipp 588) Beispieldatei Nachricht zum Beitrag an Autor Nach oben

Wie kann ich ständig einen Lauftext anzeigen lassen?

Dafür gibt es mehrere Möglichkeiten mit jeweiligen Vor- und Nachteilen. Deshalb ist dies etwas vom jeweilgen Einsatz abhängig.

Dieses Add-In stellt im Menüband die Möglichkeit zur Verfügung, einen Text einzugeben und den per Userform anzeigen zu lassen. Diese Userform ist nichtmodal; man kann also ganz normal in Excel arbeiten, während diese angezeigt wird. Ausnahme: Bei Exceleinstellungen (bzw. -versionen), bei denen Mappen in verschiedenen Instanzen angezeigt werden, kann der Lauftext durch darüber liegende Dateien verdeckt werden.

Download: lauftext_userform _timer.xlam

Makros immer zur Verfügung stellenTipp

Kategorie: Basics ▸ VBA

(Tipp 102) Nachricht zum Beitrag an Autor Nach oben

Wie kann man erreichen, daß die Makros immer zur Verfügung stehen, egal, welche Mappe gerade offen ist?

Makros werden in der Regel in der Mappe gespeichert, in der sie benötigt werden. Aber es gibt auch Makros, die immer zur Verfügung stehen sollen, die also sofort beim Aufruf von Excel bereit sein sollen.

Häufig liest man hierzu die Empfehlung, man solle die Makros in der sogenannten Persönlichen Makroarbeitsmappe speichern. Diese Methode hat jedoch gravierende Nachteile. Besser ist es, wenn man sich Add-Ins erstellt und diese über den Add-Ins-Manager einblendet.

Erstellen eines Add-Ins

  1. Zuerst erstellt man ganz normal seine Makros/VBA-Routinen, indem man sie aufzeichnet oder selbst schreibt (siehe hierzu auch Wo gibt man nun die Makros ein?).
  2. Anschließend wählt man in Excel in der Mappe, in der sich die Makros befinden, den Befehl Datei - Speichern unter und gibt einen aussagekräftigen Dateinamen ein.
  3. Dann wählt man im Dialogfeld ganz unten den Dateityp Microsoft Excel-Add-In (*.xlam). Daraufhin wechselt Excel automatisch in den Pfad, in dem sich standardmäßig die Add-Ins befinden - man kann den Ordner auch wechseln. Hauptsache ist natürlich, dass man später weiß, wohin man gespeichert hat.
  4. Mit einem Klick auf Speichern steht das Add-In sofort zur Verfügung. Excel speichert es und ergänzt den Namen mit der Endung .xlam.

Nun ist das Add-In gespeichert und steht zur Verfügung, arbeiten kann man damit aber noch nicht. Um das Add-In zu aktivieren, geht man wie folgt vor:

Einbinden des Add-Ins

Aktuell
  1. Datei ▸ Optionen
  2. Add-Ins
  3. Verwalten: Excel-Add-Ins ▸ Los
  4. Durchsuchen
  5. Add-In-Datei suchen
  6. OK
  7. Prüfen, dass das Add-In in der Liste enthalten und das Häkchen gesetzt ist
  8. OK
Ab Excel 2007
  1. Office-Schaltfläche (oben links)
  2. Excel-Optionen
  3. Add-Ins
  4. Verwalten: Add-Ins > Gehe zu ...
  5. Durchsuchen
  6. Add-In-Datei suchen
  7. OK
  8. Prüfen, dass das Add-In in der Liste enthalten und das Häkchen gesetzt ist
  9. OK
Frühere Excel-Versionen
  1. Extras
  2. Add-Ins-Manager
  3. Durchsuchen
  4. Add-In-Datei suchen
  5. OK
  6. Prüfen, dass das Add-In in der Liste enthalten und das Häkchen gesetzt ist
  7. OK

Fertig - nun stehen alle Makros dieses Add-Ins immer zur Verfügung, auch, wenn man Excel beendet und neu startet.

Nachträgliches Bearbeiten der Makros

Möchte man die Makros nachträglich ändern oder ergänzen, ist dies auch kein Problem. Man wechselt mit der Tastenkombination Alt + F11 in den VBA-Editor, in dem man nun (standardmäßig) links oben im Projektexplorer den Namen des Add-Ins findet. Doppelklickt man darauf, werden die einzelnen Elemente (Tabellen, Module, usw.) sichtbar und durch einen Doppelklick auf das entsprechende Element sieht man den Code der/des Makros bereits vor sich und kann ihn bearbeiten. Nicht vergessen, zu speichern!

Add-In in normale Excel-Datei umwandeln

Normalerweise sieht man das Add-In nur im VBA-Editor, nicht aber in Excel. Manchmal möchte man aber aus dem Add-In wieder eine "normale" Mappe erstellen, damit man die Tabellen in Excel bearbeiten kann. Das ist auch kein Problem. Man gibt dazu einfach irgendwo diesen Code ein und führt ihn aus. Wechselt man nun nach Excel, hat man als Mappe das Add-In vor sich und kann wie in einer normalen Excelmappe arbeiten:

Sub Test() Workbooks("Name_des_Add-ins.xla").Isaddin = False End Sub

personl.xls

Auch mit einer Datei mit dem Namen PERSONAL.XLSB kann man Makros allgemein verfügbar machen. Dazu wählt man folgende Schritte:

  1. Menü Extras - Makro - Aufzeichnen
  2. Namen des Makros eingeben
  3. Bei Makro speichern in wählen: Persönliche Makroarbeitsmappe
  4. Schritte durchführen, die das Makro später ausführen soll
  5. Aufzeichnung beenden
  6. Excel beenden, Frage nach Speichern mit Ja beantworten
  7. Excel neu starten

Nun ist die Datei PERSONAL.XLSB automatisch gespeichert und wird bei jedem Excelstart mitgeöffnet. Sie kann auch bearbeitet werden, indem man mit Alt + F11 in den Editor wechselt.

Auch wenn oft empfohlen wird, zentrale Makros in dieser Datei zu speichern, rate ich davon ab. Im Unterschied zu einem Add-In ist sie eine Mappe, die beim Excelstart mit aufgerufen wird und kann über das Menü Fenster - Einblenden eingeblendet werden. Daraus könnten sich Probleme ergeben, wenn mit der Workbooks-Auflistung gearbeitet wird. So wirkt sich z. B. folgender Code auch auf die PERSONAL.XLSB aus:

For each x in Workbooks ... Next

Auf ein Add-In wirkt es sich nicht aus.



Objekt und UnterobjektTipp

Kategorie: Basics ▸ OOP

(Tipp 217) Nachricht zum Beitrag an Autor Nach oben

Viele Objekte können aus weiteren bestehen. Wenn man von einem Objekt auf ein Unterobjekt eines anderen Objektes zugreifen möchte, muss man immer zuerst das übergeordnete Objekt und dahinter mit einem Punkt das untergeordnete Objekt schreiben.

Beispiel: Ein Auto hat ein Schloss. Wenn man den Schlüssel reinsteckt, würde man schreiben:

Schloss.Öffnen

Sitzt man aber in einem anderen Auto und möchte von dort aus sein Auto mit einer Fernbedienung öffnen, müsste man schreiben:

MeinAuto.Schloss.Öffnen

Schließlich steht man ja in dem Moment nicht an seinem Auto und muss deshalb sagen, welches Autoschloss geöffnet werden soll.

Objekte, Eigenschaften und MethodenTipp

Kategorie: Basics ▸ OOP

(Tipp 215) Nachricht zum Beitrag an Autor Nach oben

Es ist nicht leicht, auf eine Variante ohne Select und Activate umzusteigen, aber es lohnt sich.

Vielleicht zunächst etwas Grundsätzliches:

Um objektorientiert zu arbeiten muss man wissen, was in Excel Objekte sind: Mappen, Tabellen, Spalten, Zeilen, Zellen, Userformen, usw.

Jedes Objekt hat Eigenschaften.
Das heißt, man kann die Frage stellen: Wie ist es? Im Vergleich zu einem Auto kann man also fragen: Wie ist die Farbe des Autos?

Jedem Objekt stehen aber auch Methoden zur Verfügung.
Dann kann man die Frage stellen: Was soll damit geschehen? Beim Auto wäre das: Was soll das Auto machen?

Objektorientierte ProgrammierungTipp

Kategorie: Basics ▸ OOP

(Tipp 214) Nachricht zum Beitrag an Autor Nach oben

Immer wieder wird nach den Nachteilen von Select und Activate gefragt oder es wird darauf eingegangen. Leider wird es auch immer wieder genutzt - kein Wunder, denn selbst der Makro-Recorder zeichnet das ja so auf.

Fakt ist jedoch: Diese Anweisungen sollte man vermeiden, wo es immer geht.

Der Grund ist, dass man Blätter und Zellen immer erst aktivieren muss, wenn man mit ihnen arbeitet. Das ergibt nicht nur ein unschönes Bildschirmflackern (das man allerdings abstellen kann), sondern sorgt durch die Rechenbelastung auch dafür, dass die Routinen stark verlangsamt werden. Außerdem spart man sich viel Code, wenn man Objekte direkt anspricht; die Programmierung wird also viel übersichtlicher.

SyntaxTipp

Kategorie: Basics ▸ OOP

(Tipp 216) Nachricht zum Beitrag an Autor Nach oben

Wenn man Objekte mit deren Methoden und Eigenschaften verbinden möchte, geschieht dies grundsätzlich mit einem Punkt. Dabei wird zuerst das Objekt geschrieben, dann der Punkt und dann die Methode/Eigenschaft.

Beispiel Methode: Auto.Fahre

Anders ausgedrückt: damit.soll das passieren

Beispiel: ActiveWorkbook.close

Also: Aktive Mappe.schließen. Das ist Objekt.Methode.

Beispiel Eigenschaft: Auto.Farbe

Weiterhin kann man auch schreiben das.soll sein = so

Beispiel: Application.ScreenUpdating = true

Also: Anwendung.Bildschirmaktualisierung = wahr. Das wäre dann Objekt.Eigenschaft.