Programm-Schleifen in VBA

Mehrfache Ausführung (loop) von Programm-Teilen

Eine der größten Stärken eines Computers ist die Fähigkeit, Anweisungen rasch und oft zu in Schleifen (loops) wiederholen. Diese Seite demonstriert einige Möglichkeiten, Schleifen mit VBA zu programmieren.
VBA VBA Visual Basic for Applications - Programm-Fluß-Kontrolle
For ... Next Schleife mit Zähler
For Each Schleife für alle Elemente einer Liste
Bedingungen Schleife mit Bedingung (Allgemein)
While ... Wend Standard-Schleife mit Bedingung
Varianten Varianten der Schleife mit Bedingung:
Do While ... Loop, Do ... Loop While, Do Until ... Loop, Do ... Loop Until
Abbruch mit Exit Do
OnTime Zeit-Schleife (z.B. zu jeder Sekunde . . )
GoTo Schlechte Programmierung . .
Verwandte Themen Bedingte Verzweigungen, Unterprogramme, Arrays

For ... Next   -   Schleife mit Zähler

Diese Anweisung bewirkt, dass ein Programm-Block mehrfach wiederholt ausgeführt wird.
Eine ganzzahlige Variable (Integer) wird als Schleifen-Zähler verwendet. Sie wird vor Beginn der Schleife auf einen Anfang-Wert gesetzt und in jedem Schleifen-Durchlauf um +1 erhöht. Die Schleife wird so oft durchlaufen, bis der Zähler den Ende-Wert erreicht hat.
Optional kann man die Schritt-Weite (Standard +1) auch auf andere ganze Zahlen setzen. Bei negativer Schrittweite wird abwärts gezählt (countdown), in diesem Fall ist der Endwert (meist 0) kleiner als der Anfangswert.
Innerhalb der Schleife befindet sich der Programm-Block Anweisungen, der in jedem Schleifen-Durchlauf ausgeführt wird. Wenn sich darunter eine Exit For Anweisung befindet, wird die Schleife sofort beendet, auch vor dem Erreichen des Ende-Werts.
Anweisung Next beendet die Schleife. Danach folgende Anweisungen werden nur einmal ausgeführt.
For Zähler = Anfang To Ende [Step Schritt]
[Anweisungen]
[Exit For]
[Anweisungen]
Next [Zähler]
In diesem (vereinfachten) Beispiel wird eine For-Schleife zur Berechnung der Faktoriellen-Funktion verwendet. Dabei werden alle Zahlen 1..n miteinander multipliziert.
Für n=1 wird die Schleife 1mal durchlaufen und ergibt faktorielle=1
Für n=2 wird die Schleife 2mal durchlaufen und ergibt faktorielle=2
Wenn man f mit dem Typ Integer anlegt, kann die Funktion maximal bis faktorielle(7)=5040 rechnen, mit dem Typ Long bis faktorielle(12)=479001600
Function faktorielle(n)
Dim i As Integer
Dim f As Long
f = 1
For i = 1 To n
f = f * i
Next
faktorielle = f
End Function

Verschachtelte Schleifen:

Innerhalb einer Schleife können weitere Schleifen eingesetzt werden. Jede davon muss ihren eigenen Zähler führen. Der Programm-Block des Beispiels besteht aus einer einzigen Zeile, in der beide Schleifen-Zähler (i und j) verwendet werden. Die Schleifen-Anweisungen werden hier 100mal durchlaufen, z.B.
Für i=0 und j=5 wird m=5
Für i=3 und j=6 wird m=36
usw.
For i = 0 To 9
For j = 0 To 9
m = 10 * i + j
Next j
Next i

Arrays

werden oft in Schleifen verarbeitet. Das Beispiel füllt die Elemente eines Arrays z mit den Quadraten der Index-Zahlen, z.B. wird z(5)=25 gesetzt usw.
Details zu Arrays in VBA
Dim i As Integer
Dim z(100) As Double
For i = 0 To 100
z(i) = i * i
Next i

Vorsicht !

Ändern sie niemals den Wert des Schleifen-Zählers durch Programm-Anweisungen (obwohl das von VBA erlaubt wird). Das Ergebnis ist in anderen Programmiersprache unterschiedlich. Sie können den Zähler jedoch problemlos lesen.
Nach dem Ende der Schleife ist der Wert des Schleifen-Zählers in den meisten Programmier-Sprachen (nicht in VBA) unbestimmt. Wenn sie den Wert nachher noch benötigen, sollten sie ihn rechtzeitig an eine andere Variable (hier an j ) zuweisen.
Sub nixgut()
Dim i, jAs Integer
For i = 0 To 4
MsgBox ("i=" & i)
i = i + 1
j = i
Next
' j kann verwendet werden
End Sub

For Each ... Next - Schleife über alle Elemente einer Liste

Lösung mit Standard-Methoden

Schleifen werden oft dazu verwendet, alle Bestandteile einer Liste (alle Sub-Elemente eines Objekts) zu durchlaufen. Dazu kann man die Anzahl der Elemente (Eigenschaft Count) ermitteln und in einer 'gewöhnlichen' For-Schleife einsetzen.

Im Beispiel wird ein Bereich (Range) an die Function sumrange übergeben, z.B. als Kalkulations-Formel =sumrange(A1:C3)
Die Funktion ermittelt die Anzahl der Zellen ( r.Count oder r.CellsCount ) und durchläuft alle Zellen Cells(i) in einer For-Schleife. Dabei werden die enthaltenen Zahlen-Werte (Value) addiert und zurückgegeben.
Dieses Beispiel hat nur Demo-Wert, da es das gleiche Ergebnis gibt wie die Standard-Funktion =SUMME(A1:C3) - Es kann allerdings leicht mit dieser Funktion kontrolliert werden.
Function sumrange(r As Range)
Dim i As Integer
Dim s As Double
s = 0
For i = 1 To r.Cells.Count
s = s + r.Cells(i).Value
Next
sumrange = s
End Function
VBA bietet für diesen Fall die spezialisierte Anweisung For Each
Vorteil und Nachteil zugleich ist, dass man den Index (die fortlaufende Nummer) der Sub-Elemente nicht kennt / kennen muss:
For Each Element In Gruppe
[Anweisungen]
[Exit For]
[Anweisungen]
Next [Element]

Lösung mit For Each

Das Beispiel ist genauso aufgebaut wie im vorigen Absatz. Die Anweisung For Each weist der Variablen rc bei jedem Durchlauf ein Element der Menge r.Cells zu, d.h. rc symbolisiert je eine Zelle des Bereichs r

Analog kann man alle Arbeitsblätter oder Diagramme eines Kalkulations-Dokuments durchlaufen, alle Befehle eines Menüs, alle Säulen eines Diagramms, usw. usw.
Function sumrange2(r As Range)
Dim s As Double
Dim rc As Range
For Each rc In r.Cells
s = s + rc.Value
Next
sumrange2 = s
End Function

Vorsicht mit Arrays

Arrays kann man ebenfalls mit For Each verarbeiten. In diesem Fall kann man die Array-Elemente jedoch nur lesen, nicht schreiben (ändern) !
Das Beispiel durchläuft ein Array ia und kopiert (!) in jedem Durchlauf ein Element ia(*) in die Variable i
Dabei wird in der Variablen is die Summe aller Elemente berechnet. Auch der zweite Befehl in der Schleife (Erhöhung von i um +1) läuft fehlerfrei, ändert jedoch nur die Variable i und nicht das gerade bearbeitete Array-Element !
Details zu Arrays in VBA
Dim i, ia(10), is As Integer
. . .
is = 0
For Each i In ia
is = is + i
i = i + 1
Next

Schleifen mit Bedingung

Solche Schleifen werden wiederholt durchlaufen, solange die logische Bedingung den Wert True hat.
While Bedingung
[Anweisungen]
Wend
Als Bedingung ist jeder logische Ausdruck geeignet, d.h. jeder Ausdruck, dessen Ergebnis entweder True oder False ergibt.
Der Programm-Block Anweisungen1 wird dann ausgeführt, wenn der logische Test von Bedingung1 "Wahr" (True) ergibt.

Leider sieht in VBA der Operator für eine Wert-Zuweisung (a=0) genauso aus wie der Vergleichs-Operator If(a=0) ...
Nur der Context (Zusammenhang) entscheidet, welche Form zutrifft. Modernen Programmiersprachen unterscheiden diese beiden Fälle eindeutig.
Beispiele für Logische Ausdrücke:
True, False
a=1, a<>b,
b>2, c<3, d>=4, e<=f
(a<1 and b>2), (c=1 or c=2), ((a<0 and b>0) or c=0)

Auch Zahlenwerte können als logische Ausdrücke dienen:
Die Zahl 0 entspricht False
Alle anderen Zahlen entsprechen True
Sonderfälle:

Endlos-Schleife

Wenn die Bedingung niemals False wird, dann wird die Schleife 'unendlich' oft ausgeführt - Dieser unangenehme Programmier-Fehler passiert fast allen AnfängerInnen.

Schleife wird übersprungen

Wenn die Bedingung bereits zu Beginn der Schleife False ist, dann wird sie niemals ausgeführt.
Sicherung gegen Endlos-Schleifen
Zumindest während der Entwicklung sollten sie jede Schleife gegen endloses Durchlaufen sichern. Richten sie einen Zähler ein, der die Schleife nach 100 (1000, ..) Durchläufen sicher abschaltet - So können sie die Schleife im normalen Bereich testen, aber Endlos-Fälle abfangen.
Wenn das Programm ausreichend getestet ist, kann die Sicherung entfernt werden.
Zähler=100
While (Bedingung And Zähler>0)
[Anweisungen]
Zähler=Zähler-1
Wend

Verknüpfte Bedingung

Die Bedingung von Schleifen wird häufig aus mehreren Elementen zusammengesetzt. Dazu stehen die logischen Operatoren Not (Umkehrung), And und Or zur Verfügung.
And - Alle verknüpften Elemente müssen True sein, damit der gesamte Ausdruck True wird.
Or - Mindestens eines der verknüpften Elemente muss True sein, damit der gesamte Ausdruck True wird.

Sichere Bedingung

Wenn sie mit einem Zähler arbeiten, dann soll die Schleife am gewünschten End-Wert abgebrochen werden.
Prüfen sie in solchen Fällen nicht nur auf Gleichheit mit dem Endwert, sondern auch auf dessen Überschreitung. Das sollten sie immer tun - auch dann, wenn der Zähler nach ihrer Ansicht den Endwert keinesfalls überschreiten kann.
Beispiel:
Ein Zähler beginnt bei i=0 und die Schleife soll 100mal laufen. Formulieren sie
While i<100
und nicht
While i<>100
Wenn sie abwärts zählen (countdown), dann formulieren sie z.B.
While i>0

Syntax-Varianten

Leider bietet VBA mehrere überflüssige Syntax-Varianten. Das führt bei AnfängerInnen zu Mißverständnissen, Profis verwenden diese Varianten nicht. Darüber hinaus erschweren sie die Übersetzung von Programmen in andere Programmiersprachen.
Die logische Bedingung kann entweder am Anfang oder am Ende jedes Schleifen-Durchlaufs getestet werden. Allgemein üblich ist nur der Test am Anfang.
Die Bedingung kann für die Ausführung (positive Logik) oder für den Abbruch der Schleife (umgekehrte Logik, unüblich) formuliert werden.

VBA-Varianten mit Test am Anfang: VBA-Varianten mit Test am Ende: Zum Vergleich enthält jede vorgestellte Variante ein Beispiel, in welchem die Schleife genau 100mal durchlaufen wird.

While verwenden ! Tipp:
Verwenden sie nur eine Variante, am besten die 'klassische' While-Schleife. Hier erfolgt der Test in positiver Logik am Anfang der Schleife. Diese Variante finden sie in allen gängigen Programmiersprachen.

Vorsicht ! Vorsicht:
Wenn die Bedingung erst am Ende der Schleife geprüft wird, dann wird die Schleife in jedem Fall einmal durchlaufen - auch dann, wenn die Bedingung niemals True war !

While-Schleife While .. Wend   -   Standard-Schleife mit Bedingung

Schleifen in dieser Form werden von jeder gängigen Programmiersprache angeboten.
Daher ist diese Syntax jeder anderen Variante vorzuziehen:
Die Prüfung der Bedingung erfolgt in positiver Logik am Anfang jedes Schleifen-Durchgangs.
Das bedeutet Ausführung der Anweisungen, wenn (solange) die Bedingung True ist.
Allgemeine Angaben zu Schleifen mit Bedingung
While Bedingung
[Anweisungen]
Wend
Beispiel für eine genau 100mal ausgeführte Schleife.
Tipp: Vergessen sie bei der Programmierung nicht darauf, den Zähler zu erhöhen, sonst erzeugen sie eine Endlos-Schleife. Setzen sie diese Anweisung entweder als erste (unüblich) oder als letzte Programmzeile (Standard) in die Schleife, niemals 'versteckt' zwischen andere Anweisungen.
Dim i As Integer
i = 0
While i < 100
'Anweisungen
i = i + 1
Wend
Dieses Beispiel zeigt eine typische Anwendung der While-Schleife. Die Funktion bits_for berechnet die Anzahl Bits, welche für die Darstellung einer ganzen Zahl x notwendig sind.
Dazu wird die Zahl x so oft halbiert, bis ihr Wert x<=1 ist. Ein Zähler z zählt die Anzahl der Durchläufe und wird als Ergebnis zurückgegeben.

MathematikerInnen formulieren lieber
bits_for(x) = ceil(ln(x)/ln(2))
aber erstens bietet VBA keine ceiling-(Aufrunden)-Funktion und zweitens dauert die Berechnung der Logarithmen für kleine x länger als ein paar Schleifen . .
Function bits_for(x)
Dim z As Integer
z = 0
While x > 1
x = x / 2
z = z + 1
Wend
bits_for = z
End Function

Animation

In Animationen werden oft bewusst Endlos-Schleifen eingesetzt. Sie werden längere Zeit hindurch ausgeführt, z.B. solange ein Kalkulations-Blatt geöffnet ist.
Details zu Animationen in VBA

Wenn eine Animation interaktiv gesteuert wird, dann muss man sie mit einem Ereignis (event) abschalten, z.B. bei Klick auf eine Stop-Taste.

Do While .. Loop   -   Schleife

Die Prüfung der Bedingung erfolgt in positiver Logik am Anfang jedes Schleifen-Durchgangs.
Das bedeutet Ausführung der Anweisungen, wenn (solange) die Bedingung True ist.
Diese Variante entspricht genau der While-Schleife und wird am besten durch diese ersetzt.
Allgemeine Angaben zu Schleifen mit Bedingung
Do While {Bedingung]
[Anweisungen]
[Exit Do]
[Anweisungen]
Loop
Beispiel für eine genau 100mal ausgeführte Schleife
Dim i As Integer
i = 0
Do While i < 100
'Anweisungen
i = i + 1
Loop

Abbruch

Alle Varianten der Do-Schleife werden abgebrochen, wenn in den Anweisungen der Schleife ein Exit Do enthalten ist. Das ist natürlich nur in einer bedingten Verzweigung sinnvoll:
If ... Then Exit Do

Alternativ können sie jede Schleife abbrechen, wenn an Stelle der Exit Do Anweisung eine der Schleifen-Bedingungen so geändert wird, dass sie abgebrochen wird. Das mag umständlicher erscheinen, zwingt jedoch zu sauberer Programmierung und lässt sich problemlos in jede andere Programmiersprache übertragen.

Do .. Loop While   -   Schleife

Die Prüfung der Bedingung erfolgt in positiver Logik am Ende jedes Schleifen-Durchgangs.
Das bedeutet Fortsetzung der Anweisungen, wenn (solange) die Bedingung True ist.
Allgemeine Angaben zu Schleifen mit Bedingung
Do
[Anweisungen]
[Exit Do]
[Anweisungen]
Loop While [Bedingung]
Beispiel für eine genau 100mal ausgeführte Schleife.
Vorsicht - Diese Schleife wird in jedem Fall mindestens 1mal ausgeführt, auch dann wenn die Bedingung niemals True ist.
Dim i As Integer
i = 0
Do
'Anweisungen
i = i + 1
Loop While i<100

Do Until .. Loop   -   Schleife

Die Prüfung der Bedingung erfolgt in umgekehrter Logik am Anfang jedes Schleifen-Durchgangs.
Das bedeutet Ausführung der Anweisungen, wenn (solange) die Bedingung False ist.
Allgemeine Angaben zu Schleifen mit Bedingung
Do Until [Bedingung]
[Anweisungen]
[Exit Do]
[Anweisungen]
Loop
Beispiel für eine genau 100mal ausgeführte Schleife
Dim i As Integer
i = 0
Do Until i >= 100
'Anweisungen
i = i + 1
Loop

Do Loop .. Until   -   Schleife

Die Prüfung der Bedingung erfolgt in umgekehrter Logik am Ende jedes Schleifen-Durchgangs.
Das bedeutet Fortsetzung der Anweisungen, wenn (solange) die Bedingung False ist.
Allgemeine Angaben zu Schleifen mit Bedingung
Do
[Anweisungen]
[Exit Do]
[Anweisungen]
Loop Until [Bedingung]
Beispiel für eine genau 100mal ausgeführte Schleife.
Vorsicht - Diese Schleife wird in jedem Fall mindestens 1mal ausgeführt, auch dann wenn die Bedingung niemals False ist.
Dim i As Integer
i = 0
Do
'Anweisungen
i = i + 1
Loop Until i>=100

Zeit - 'Schleife'

Wenn sich ein Programm nach einer Wartezeit selbst aufruft, dann wirkt das wie eine (endlose) Schleife, obwohl es sich um Ereignis-Programmierung handelt.
Das Beispiel-Sub wird - einmal gestartet - pro Sekunde einmal ausgeführt.
Details zur Programmierung von Zeit-Ereignissen (events) in VBA.
Sub jede_sekunde()
' Anweisungen
Application.OnTime Now + TimeValue("00:00:01"), "jede_sekunde"
End Sub

GoTo-Schleife GoTo - 'Schleife'

Diese Variante ist ein schlechtes Beispiel. Es wird hier nur angeführt, weil man gelegentlich auf solche Programme trifft.
Sie sollten solche Programmteile so bald wie möglich durch For oder While Schleifen ersetzen.
Ausnahme: Programme in Maschinensprache (Assembler) verwenden solche Konstruktionen.
Dim i As Integer
i = 0
za:
'Anweisungen
i = i + 1
If i<100 Then GoTo za