Sobald dein Code wächst, zerlegst du ihn in kleine, benannte Bausteine: Prozeduren. Jede erledigt eine Aufgabe, hat einen sprechenden Namen und lässt sich von überall aufrufen. Das hält Code lesbar und vermeidet Wiederholung.
Sub oder Function?
Es gibt zwei Arten von Prozeduren, und der Unterschied ist einfach:
- Eine
Subtut etwas — sie gibt keinen Wert zurück. - Eine
Functionberechnet etwas — sie gibt einen Wert zurück.
' Sub: erledigt eine Aktion
Public Sub ZeigeMeldung(ByVal text As String)
MsgBox text, vbInformation, "Hinweis"
End Sub
' Function: liefert ein Ergebnis
Public Function Netto(ByVal brutto As Double, ByVal satz As Double) As Double
Netto = brutto / (1 + satz)
End Function
Faustregel: Brauchst du ein Ergebnis, das du weiterverwendest, nimm eine
Function. Willst du nur etwas auslösen (Meldung, Import, Speichern), reicht eine
Sub.
Rückgabewerte
Eine Function gibt ihren Wert zurück, indem du dem Funktionsnamen etwas
zuweist. Der Typ nach As legt fest, was zurückkommt:
Public Function Rabatt(ByVal betrag As Currency) As Currency
If betrag > 100 Then
Rabatt = betrag * 0.1
Else
Rabatt = 0
End If
End Function
Der zuletzt zugewiesene Wert wird zurückgegeben. Weist du gar nichts zu, kommt
der Standardwert des Typs zurück (0, "" oder Null).
Prozeduren aufrufen
Eine Sub rufst du einfach mit ihrem Namen auf, die Argumente folgen ohne
Klammern:
ZeigeMeldung "Import abgeschlossen"
Eine Function nutzt du dort, wo ein Wert erwartet wird — dann mit Klammern:
Dim n As Double
n = Netto(119, 0.19) ' 100
Debug.Print Netto(238, 0.19) ' 200
Merke: Sobald du das Ergebnis einer Prozedur einer Variablen zuweist oder als Argument weiterreichst, brauchst du Klammern. Rufst du eine
Subfreistehend auf, lässt du sie weg. (Das veralteteCallerzwingt immer Klammern.)
ByVal vs. ByRef
Wie ein Argument übergeben wird, entscheidet, ob die aufgerufene Prozedur den Originalwert verändern kann:
ByValübergibt eine Kopie. Änderungen bleiben in der Prozedur.ByRefübergibt einen Verweis auf das Original. Änderungen wirken zurück.
Public Sub MitKopie(ByVal x As Long)
x = x * 2 ' ändert nur die Kopie
End Sub
Public Sub MitVerweis(ByRef x As Long)
x = x * 2 ' ändert das Original beim Aufrufer
End Sub
Public Sub Test()
Dim wert As Long
wert = 10
MitKopie wert
Debug.Print wert ' 10 – unverändert
MitVerweis wert
Debug.Print wert ' 20 – verändert
End Sub
In VBA ist
ByRefdie Voreinstellung, wenn du nichts angibst. Das ist eine häufige Fehlerquelle: Eine Prozedur ändert versehentlich eine Variable des Aufrufers. Schreib deshalb standardmäßigByValdavor, außer du willst den Wert bewusst zurückgeben.
Optionale Argumente
Mit Optional machst du ein Argument freiwillig. Gib ihm am besten einen
Standardwert, der greift, wenn der Aufrufer nichts übergibt:
Public Function Begruessung(ByVal name As String, _
Optional ByVal anrede As String = "Hallo") As String
Begruessung = anrede & " " & name & "!"
End Function
Public Sub Test2()
Debug.Print Begruessung("Ante") ' Hallo Ante!
Debug.Print Begruessung("Ante", "Moin") ' Moin Ante!
End Sub
Optionale Argumente müssen am Ende der Argumentliste stehen. Ohne
Standardwert kannst du mit IsMissing prüfen, ob etwas übergeben wurde — das
funktioniert allerdings nur bei Variant-Argumenten.
Gültigkeitsbereich: Public oder Private
Public und Private steuern, von wo eine Prozedur aufrufbar ist:
| Schlüsselwort | Sichtbar in | Einsatz |
|---|---|---|
Public | im ganzen Projekt | Hilfsfunktionen, die überall gebraucht werden |
Private | nur im eigenen Modul | interne Helfer, Ereignisprozeduren |
' In Modul "modUtil"
Public Function Steuer(ByVal betrag As Double) As Double
Steuer = betrag * 0.19
End Function
Private Sub NurHier()
' von außerhalb dieses Moduls nicht aufrufbar
End Sub
Ereignisprozeduren hinter Formularen (Private Sub cmdOK_Click()) sind fast immer
Private — sie gehören nur zu diesem Formular.
Modul- vs. Prozedurebene
Auch wo du deklarierst, bestimmt die Reichweite:
- Ein
Diminnerhalb einer Prozedur gilt nur dort und ist nach dem Ende weg. - Ein
DimoderPrivateoben im Modul (vor der ersten Prozedur) gilt für alle Prozeduren des Moduls. - Ein
Publicoben in einem Standardmodul gilt im gesamten Projekt.
Option Explicit
Private mZaehler As Long ' modulweit, überlebt Prozeduraufrufe
Public Sub HochZaehlen()
Dim lokal As Long ' nur hier gültig
lokal = lokal + 1
mZaehler = mZaehler + 1
Debug.Print lokal, mZaehler
End Sub
Rufst du HochZaehlen dreimal auf, bleibt lokal immer 1, während mZaehler
auf 3 steigt. Halte Variablen so lokal wie möglich — das macht Fehler leichter
auffindbar.
Eigene Funktionen in Abfragen und Formularen
Ein großer Vorteil von Access: Public-Funktionen aus Standardmodulen kannst du
direkt in Abfragen und Steuerelementen verwenden — als wären sie
eingebaut. Beispiel-Funktion:
Public Function VollName(ByVal vorname As String, _
ByVal nachname As String) As String
VollName = Trim(nachname & ", " & vorname)
End Function
In einer Abfrage als berechnetes Feld:
SELECT VollName([Vorname], [Nachname]) AS Anzeigename
FROM Kunden;
Oder als Steuerelementinhalt eines Textfelds im Formular:
=VollName([Vorname]; [Nachname])
Das klappt nur mit
Public-Funktionen in Standardmodulen — nicht mit Funktionen, die in einem Formular- oder Berichtsmodul stehen. Lege wiederverwendbare Funktionen deshalb in einem eigenen Modul wiemodFunktionenab.
Zusammengefasst
Subtut etwas,Functiongibt einen Wert zurück (Zuweisung an den Funktionsnamen).- Aufruf:
Subfreistehend ohne Klammern,Functionmit Klammern, wo ein Wert erwartet wird. ByValübergibt eine Kopie,ByRef(Voreinstellung!) das Original — nimm im ZweifelByVal.Optionalmit Standardwert macht Argumente freiwillig; sie stehen am Ende der Liste.Public/Privateund der Deklarationsort steuern den Gültigkeitsbereich;Public-Funktionen laufen auch in Abfragen und Formularen.