Variablen

Aus VBA-wiki
Version vom 28. Januar 2023, 00:36 Uhr von Pwania (Diskussion | Beiträge)
(Unterschied) ← Nächstältere Version | Aktuelle Version (Unterschied) | Nächstjüngere Version → (Unterschied)
Zur Navigation springen Zur Suche springen

Eine Variable ist ein Speicherort, an dem ein Wert abgelegt werden kann, der später in der Programmierung abgerufen oder verändert werden soll.

Variablen anlegen

Deklaration

Um eine Variable verwenden zu können, muss sie deklariert werden. Damit wird der Speicherort reserviert und der Name der Variable dient als Kennung, damit später auf genau diesen Wert zugegriffen werden kann.

Der reservierte Platz und die Art des Speicherplatzes wird mit dem angegebenen Datentyp bestimmt. So wird bei der Deklaration festgelegt, ob z. B. eine Zahl oder ein Text oder ein Datum gespeichert wird.

Den Datentyp kann man nur bei der Deklaration angeben und später nicht ändern.

Bei der Deklaration können mehrere Variablen in einer Zeile gemeinsam angegeben werden und werden dann durch Kommata voneinander getrennt:

Dim strName As String, strAddress As String
Public FirstName As String, LastName As String, Phone as String 

Bitte beachten:

  • Sie können zwar mehrere Variablen von verschiedenen Datentypen in einer Zeile deklarieren, sollten dies jedoch vermeiden, um Ihres Programmcode nicht unnötig kompliziert zu gestalten!
  • Wenn Sie mehrere Variablen in einer Zeile deklarieren, müssen Sie jedes Mal mit 'As' den Datentyp angeben, sonst wird die Variable als 'Variant' deklariert.

Datentyp

Der Datentyp wird bei allen Variablen mit dem Schüsselwort As und dem Bezeichner des Datentyps angegeben.

Eine vollständige Liste der in VBA möglichen Datentypen finden Sie hier: Datentypen

Benennung

Um den Zweck der Variablen klar zu kennzeichnen, sollten Sie eindeutige, sprechende Namen wählen, welche jederzeit und für jedermann und innerhalb des Kontextes eine klare Bedeutung haben.

Beispiele:

Dim strFirstName As String, strLastName As String

Die Bezeichnung und der Datentyp, welcher Teil des Namens ist (im Beispiel das vorangestellte 'str') lassen keinen Zweifel zu, welche Daten diese Variablen enthalten.

Der Grund für die ausdrückliche Angabe des Datentyps auch im Variablennamen wird mit diesem Beispiel verdeutlicht:

Dim strItem As String
Dim lngItem As Long
Dim colCollection As New Collection

colCollection.Add "One"
colCollection.Add "Two"
For lngItem = 1 To colCollection.Count
    strItem = colCollection.Item(lngItem)
Next lngItem

Der Name 'Item' wird zweimal unabhängig voneinander belegt, einmal als Zeichenkette, die einen Wert entgegennimmt, und dann als Zählvariable für die For-Schleife. In beiden Fällen ist der Name 'Item' gerechtfertigt, durch das vorangestellte 'str' bzw. 'lng' können beide trotzdem klar voneinander unterschieden werden.

Weitere Angaben zur Bezeichnung des Datentyps im Variablennamen finden Sie im Anhang.

Reihenfolge

Die Reihenfolge, in der Datentypen deklariert werden, hat keine Auswirkung auf die Ausführung des Programmcodes, durchaus jedoch auf die Lesbarkeit für uns Programmierer!

Gewöhnen Sie es sich daher gerne an, Ihre Deklarationen immer in der gleichen Reihenfolge anzulegen, um später schnell ermitteln zu können, welche Variablen schon angelegt wurden und welche Rolle diese in dieser Prozedur spielen.

Die von mir persönlich verwendete Reihenfolge gestaltet sich folgendermaßen:

  • Zeichenketten
  • Zahlenwerte nach Größe sortiert (Integer, Long, Single, Double)
  • Collections
  • Eigene Objekte (zum Beispiel Klassen), Enums und benutzerdefinierte Datentypen
  • Anwendungsobjekte wenn möglich nach Größe sortiert (zum Beispiel Bereich, Dokument, Anwendung in Word oder Zelle, Arbeitsblatt, Arbeitsmappe in Excel)

Der gespeicherte Wert

Abhängig von seinem Datentyp enthält der Speicherplatz einer Variablen bei der Deklaration einen leeren Wert:

Ursprünglicher Leerwert

  • String: "" (Leerstring)
  • Integer und Long: 0
  • Single, Double, Currency etc.: 0.0
  • Date: 00:00:00 (Uhrzeit!)
  • Boolean: False (0)
  • Array: abhängig vom Datentyp
  • Collections, Objekte, Klassen: Nothing

Werte ändern

Bitte beachten: Anders als in vielen anderen Programmiersprachen können Sie in VBA nicht bei der Deklaration der Variablen einen Wert zuweisen. Folgendes ist also nicht möglich:

Dim strValue As String = "Hallo!"     ' Verursacht einen Syntaxfehler!!!!!

Natürliche Datentypen

Um den Speicherplatz einer Variablen sinnvoll nutzen zu können, kann man ihm mit dem Ist Gleich-Operator (=) einen Wert zuweisen.

strValue = "Hallo!"

Objektvariablen

Objektvariablen bekommen mit dem zusätzlichen Schlüsselwort Set eine Instanz des Objektes zugewiesen:

 Dim objApplication As Application
 
 Set objApplication = Application 

Klassenobjekte, UserFormen und Collections müssen erst mit dem Schlüsselwort New neu erzeugt werden, bevor sie verwendet werden können:

Dim myVariables As clsVariables

Set myVariables = New clsVariables
myVariables.FirstName = "Max"
Dim myDialog As frmDialog

Set myDialog = New frmDialog
myDialog.Show
Dim colList As Collection

Set colList = New Collection
colList.Add "Value"

Wichtig: Anwendungsobjekte (Document, Workbook, Range, Font, ...) können nicht mit New neu erzeugt werden, denn sie existieren schon, sobald die Anwendung gestartet wurde. Wenn Sie ein neues Dokument erzeugen möchten, verwenden Sie stattdessen folgende Vorgehensweise:

Dim doc As Document

Set doc = Application.Documents.Add     ' erzeugt ein neues Blanko-Dokument und übergibt es an die Variable 'doc'

Zusätzlich ist eine Kurzschreibweise möglich, welche eine Objektvariable bei der Deklaration Initialisiert.

Dim myVariables As New clsVariables

myVariables.FirstName = "Max"
Dim myDialog As New frmDialog

myDialog.Show
Dim colList As New Collection

colList.Add "Value"

Diese Kurzschreibweise sollte jedoch nur dann verwendet werden, wenn absolut sicher ist, dass Sie das (Klassen-)Objekt, den Dialog oder die Collection auf jeden Fall verwenden werden.

Wenn Sie z. B. vor dem Anzeigen eines Dialoges sicher stellen müssen, dass der Dialog angezeigt werden kann, sollten Sie den Dialog erst dann Instanziieren, wenn Sie ihn auch anzeigen werden.

Dim dlg as frmDialog

If DialogMustBeShown = True Then
    Set dlg = New frmDialog
    dlg.Show
    ' ...
End If

Geltungsbereich, Lebensdauer und Formen der Deklaration

Jede Variable hat einen klar definierten Geltungsbereich, der sich aus dem Ort, an dem sie definiert wurde und den Schlüsselwörtern Private / Public ergibt:

Prozedurale Variable

Diese befindet sich innerhalb einer Prozedur (einer Funktion, einer Eigenschaft) und wird wie folgt mit dem Schlüsselwort Dim deklariert:

Sub TemporaryProceduralVariable()
    Dim strVariable As String
End Sub

Eine prozedurale Variable gilt ausschließlich innerhalb der Prozedur, in der sie definiert wurde. Die Werte sind nicht von anderen Prozeduren aus sichtbar oder veränderbar. Sobald die Prozedur verlassen wird, wird der Speicherplatz freigegeben, die Variable ist somit inklusive ihrem Wert gelöscht.

Statische prozedurale Variable

Eine mit dem Schlüsselwort Static deklarierte prozedurale Variable hat den gleichen Geltungsbereich wie die mit Dim deklarierte Variable, wird jedoch nach Verlassen der Prozedur nicht gelöscht, sondern bleibt solange erhalten, wie das Modul, in dem sich die Prozedur befindet, besteht (bei Modulen so lange das Projekt geladen ist, bei Klassen und UserForms so lange eine Instanz deren besteht).

Sub PermanentProceduralVariable() 
    Static strVariable As String 
End Sub 

So bleibt der Wert der Variable erhalten und kann bei nachfolgenden Aufrufen der Prozedur weiter verwendet werden.

Bitte beachten: Das Schlüsselwort Static darf nicht außerhalb von Prozeduren verwendet werden.

Funktionsname

Der Name einer Funktion kann innerhalb der Funktion wie eine Variable (vom Datentyp der Funktion) verwendet werden und erfüllt zusätzlich den Zweck, den Rückgabewert der Funktion entgegenzunehmen.

Private Function ApplicationName() As String 
    ApplicationName = Application.Name 
End Function 

Der Wert der Variablen, die den Funktionsnamen trägt, kann ausschließlich innerhalb der Funktion geändert werden. Der Wert der Funktion kann wie folgt abgefragt werden:

Sub Example() 
    Dim strAppName As String 
 
    strAppName = ApplicationName() 
    strAppName = ApplicationName 
End Sub 

Die leeren runden Klammern hinter dem Funktionsnamen sind beim Aufruf optional, wenn keine Parameter erwartet werden.

Der Geltungsbereich der Funktion entspricht dem Geltungsbereich aller Prozeduren:

  • Private kann nur innerhalb des (Klassen-)Moduls bzw. der UserForm verwendet werden
  • Public
    • in einem Modul: Kann jederzeit im gesamten Projekt verwendet werden
    • in einer Klasse / einer UserForm: Kann von der Instanz der Klasse / der UserForm aufgerufen und verwendet werden

Modulweite Variablen

Modulweite Variablen können von allen Prozeduren innerhalb eines Moduls verwendet werden, weil sie außerhalb einer speziellen Prozedur deklariert werden.

Sie werden im Modulkopf, also vor der Definition der ersten Prozedur, deklariert.

Hier wir nicht das Schlüsselwort Dim verwendet, sondern Private:

Option Explicit 

Private strVariable As String 

Sub FirstSub() 
    strVariable = "Hallo!" 
End Sub 

Sub SecondSub() 
    MsgBox strVariable 
End Sub 

Modulweite Variablen können nicht von Prozeduren in anderen Modulen ausgelesen oder beschrieben werden.

Bitte beachten: Modulweite und projektweite Variablen sollten nur in solchen Fällen eingesetzt werden, in denen sie sinnvoll sind, und nicht, um 'Variablen zu sparen'.

Wenn Variablen über längere Zeiträume und aus mehreren Quellen Werte behalten bzw. beziehen, kann leicht die Übersicht darunter leiden bzw. können sich unerwartete Werte in den Variablen befinden.

Der sinnvolle Einsatz von modulweiten und projektweiten Variablen wäre zum Beispiel für solche Werte, die über einen längeren Zeitraum erhalten bleiben sollen.

Projektweite Variablen

Wenn Sie Werte hinterlegen möchten, die in ihrem gesamten Projekt jederzeit zur Verfügung stehen, deklarieren Sie eine öffentliche Modulvariable mit dem Schlüsselwort Public:

Option Explicit 

Public Variable As String 

Auf diese Variable können Sie nun auch aus anderen Modulen, Klassen und Formen heraus zugreifen und von dort aus auch die Werte ändern.

Um Ihr Projekt übersichtlich zu gestalten, empfehlen wir, dass Sie projektweite Variablen, wenn möglich, in einem Modul sammeln.

Bitte beachten: Modulweite und projektweite Variablen sollten nur in solchen Fällen eingesetzt werden, in denen sie sinnvoll sind, und nicht, um 'Variablen zu sparen'.

Wenn Variablen über längere Zeiträume und aus mehreren Quellen Werte behalten bzw. beziehen, kann leicht die Übersicht darunter leiden bzw. können sich unerwartete Werte in den Variablen befinden.

Der sinnvolle Einsatz von modulweiten und projektweiten Variablen wäre zum Beispiel für solche Werte, die über einen längeren Zeitraum erhalten bleiben sollen.

Besondere Geltungsbereiche in Klassen und UserFormen

Da UserFormen eine besondere Form von Klassenmodulen sind und sich im Bezug auf Variablen identisch verhalten, werden wir in diesem Abschnitt nicht getrennt auf sie eingehen, sondern wie Klassen behandeln.

Prozedurale und private Klassen-Variablen

Prozedurale Variablen folgen den oben angegebenen Regeln; sie gelten ausschließlich innerhalb der Prozedur, in der sie definiert wurden. Mit Private deklarierte Klassen-Variablen gelten ebenfalls ausschließlich innerhalb der Klasse bzw. der UserForm.

Öffentliche Klassenvariablen

Mit Public deklarierte Klassen-Variablen stehen zusätzlich den Instanzen der Klasse zur Verfügung.

Sie können wie Eigenschaften eingesetzt werden, wenn man die Werte ungeprüft entgegennehmen kann und die Vergabe von neuen Werten nicht beeinflussen möchte.

Beispielklasse 'clsVariables':

Option Explicit 

Public FirstName As String, LastName As String, Phone As String 
Private strClassVariable As String 

Public Sub DoSomething() 
    Dim strMyValue As String 
    
    MsgBox FirstName 
End Sub

Beispielmodul 'modTest':

Option Explicit 

Sub Example() 
    Dim myVariables As clsVariables 
    
    Set myVariables = New clsVariables 
    myVariables.FirstName = "Max" 
    myVariables.LastName = "Muster" 
    myVariables.Phone = "+49 123 4656789" 
    myVariables.DoSomething 
End Sub 

Darstellung im VBA-Editor: Ausschließlich die öffentlichen Variablen und Prozeduren stehen der Instanz myVariables zur Verfügung: ClassVariables.png

Übergabeparameter

Wenn einer Prozedur ein Wert übergeben wird, wird dieser nach dem Prozedurnamen innerhalb der runden Klammern angegeben.

Mehrere Parameter werden durch Kommata getrennt.

Private Sub SingleParameter(ByVal lngValue As Long) 

End Sub
Private Sub ListOfParameters(ByVal lngValue As Long, ByVal strValue As String, ByVal dteDate As Date)

End Sub

ByVal

Der Geltungsbereich beschränkt sich mit dem Schlüsselwort ByVal wie bei prozeduralen Variablen auf die Prozedur, der sie übergeben wird.

Private Sub ParameterByVal(ByVal lngValue As Long) 

    ' ... 
    lngValue = lngValue + 1 
    '.... 
End Sub 

Private Sub Test() 
    Dim lngNumber As Long 
    
    lngNumber = 5 
    ParametersByVal lngNumber 
    Debug.Print lngNumber           ' Der Wert ist immer noch 5 
End Sub 

Das bedeutet, dass die empfangende Prozedur eine neue Variable mit dem gewünschten Wert erhält. Wenn dieser Wert innerhalb der Prozedur geändert wird, betrifft diese Änderung NICHT die Variable in der absendenden Prozedur.

ByRef

Wird ein Parameter mit dem Schlüsselwort ByRef übergeben, verhält sich die Variable innerhalb der Prozedur, an der sie übergeben wurde, identisch zu ByVal.

Aber der Wert wird nicht in einer neuen Variablen übergeben, sondern über eine Referenz auf die aufrufende Variable:

Private Sub ParametersByRef(ByRef lngValue As Long)

    ' ... 
    lngValue = lngValue + 1 
    '.... 
End Sub 

Private Sub Test() 
    Dim lngNumber As Long 
    
    lngNumber = 5 
    ParametersByRef lngNumber 
    Debug.Print lngNumber      ' Der Wert ist jetzt 6!!! 
End Sub 

Über diese Referenz erhält also die aufgerufene Prozedur Zugriff auf den Original-Speicherplatz und kann dessen Wert direkt ändern. Dies kann selbstverständlich zu großer Verwirrung führen, wenn Sie nicht mit diesem Verhalten rechnen.

Bitte beachten: Wenn Sie bei einem Parameter keine zusätzliche Angabe machen, wird standardmäßig die Übergabe ByRef vorgenommen!

Optionale Parameter

Generelles zu optionalen Parametern

Das Schlüsselwort 'Optional' gibt an, dass der beschriebene Parameter optional ist, also nicht zwingend angegeben werden muss.

In der Hilfe und in der Quickinfo (STRG + i) werden optionale Parameter in eckigen Klammern dargestellt.

Bei der 'MsgBox'-Funktion wird dies zum Beispiel deutlich: Der Prompt wird zwingend erwartet, alle weiteren Parameter sind optional und können bei Bedarf weggelassen werden.

 MsgBox(Prompt, [Buttons As VbMsgBoxStyle = vbOKOnly], [Title], [HelpFile], [Context]) As VbMsgBoxResult

Bei einer eigenen Prozedur sieht das dann so aus:

Private Sub OptionalParameter(ByVal strNecessary As String, Optional ByVal lngOptional As Long) 

End Sub

Quickinfo:

OptionalParameter(ByVal strNecessary As String, [ByVal lngOptional As Long])

Sie können für einen optionalen Parameter einen Standardwert vergeben:

Private Sub OptionalParameter(ByVal strNecessary As String, Optional ByVal lngOptional As Long = 3) 

End Sub

Der Aufruf kann nun wie folgt durchgeführt werden:

OptionalParameter "Hallo" 

oder mit zweitem Parameter

OptionalParameter "Hallo", 7 

aber niemals

OptionalParameter         ' Ganz ohne Parameter
OptionalParameter , 7     ' Nur mit Angabe des zweiten Parameters
Regeln
  • Bitte die hier gezeigte Reihenfolge einhalten ('Optional' erscheint vor 'ByVal', 'ByRef' bzw. dem Namen des Parameters).
  • Der Standardwert wird nach der Angabe des Datentyps platziert.
  • Wichtig: Nach einem optionalen Parameter können ausschließlich weitere optionale Parameter erscheinen!!! Alle benötigten Parameter stehen damit am Anfang der Parameter-Liste, optionale am Ende.

Bitte beachten: Die 'IsMissing'-Funktion soll prüfen, ob einem optionalen Parameter ein Wert übergeben wurde. Dies klappt allerdings nur für Variant-Werte!

Tipp: Wenn Sie prüfen möchten, ob ein optionaler Parameter angegeben wurde, belegen Sie ihn mit einem unwahrscheinlichen oder unmöglichen Wert:

Beispiel: Hier wird der Standardwert für 'lngRoundToDigits' mit einem nicht möglichen Wert '-1' vorbelegt:

Public Function RandomDouble(ByVal dblBottom As Double, ByVal dblTop As Double, Optional ByVal lngRoundToDigits As Long = -1) As Double

    Randomize
    RandomDouble = dblBottom + Rnd() * (dblTop - dblBottom)
    
    ' Wenn die Funktion ohne Angabe der Anzahl der Nachkommastellen aufgerufen wird, beträgt der Wert weiterhin -1,
    ' welches nicht möglich ist, denn es gibt keine negativen Nachkommastellen.
    ' Statt nun also das Ergebnis auf eine Ganzzahl zu runden (welches bei 0 der Fall wäre), kann nun mit einer If-Abfrage das Runden komplett verhindert werden:
    
    If lngRoundToDigits >= 0 Then
        RandomDouble = Round(RandomDouble, lngRoundToDigits)
    End If
End Function

Private Sub Test()
    
    Debug.Print RandomDouble(0, 5)          ' 3,75971466302872  (ungerundeter Wert)
    Debug.Print RandomDouble(0, 5, 0)       ' 4                 (auf ganze Zahl gerundet)
    Debug.Print RandomDouble(0, 5, 5)       ' 3,75971           (auf 5 Nachkommastellen gerundet)
End Sub

Arbeiten mit Optionalen Parametern

Bei Variant-Parametern können Sie mit der IsMissing-Funktion prüfen, ob der optionale Parameter übergeben wurde:

Public Sub DoSomething(Optional ByVal varWithThis As Variant)
    
    If IsMissing(varWithThis) = False Then
        MsgBox "Der Parameter wurde übergeben!"
        End If
    End Sub
Private Sub TestDoSomething()
    DoSomething ' Kein Parameter ...
    DoSomething "Irgendwas"
End Sub

Empfohlen wird jedoch, stattdessen mit dem Leerwert des Parameters oder einem unwahrscheinlichen Vorgabewert zu arbeiten:

Public Sub DoSomething(Optional ByVal strWithThis As String)
    
    If strWithThis <> "" Then
        MsgBox "Der Parameter wurde übergeben!"
    End If
End Sub
Public Sub DoSomething(Optional ByVal lngWithThis As Long =  - 43423442)

    If lngWithThis <> - 43423442 Then
        MsgBox "Der Parameter wurde übergeben!"
    End If
End Sub

Der Vorteil dieser letzten Beispiele ist, dass Sie nicht ausschließlich mit Variant-Parametern arbeiten müssen, um dann mit 'IsMissing' festzustellen, ob der Parameter verwendet wurde.

Konstanten

Eine Konstante ist ein Speicherort, an dem ein fester Wert hinterlegt werden kann. Der Wert wird bei der Deklaration angegeben und kann danach nicht wieder geändert werden.

Deklaration und Wertzuweisung

Eine Konstante wird mit dem Schlüsselwort Const deklariert, der Wert wird anschließend mit '=' zugewiesen:

Prozedurale Konstante:

Const strConstant As String = "Konstanter Wert"     ' NICHT: Dim Const strConstant As String = "Konstanter Wert"

Alle weiteren Konstanten:

Private Const strConstant As String = "Konstanter Wert" 
Public Const Constant As String = "Konstanter Wert" 

Bitte beachten: Bei konstanten Datumsangaben muss der Datumswert entweder als Zahl oder eindeutiger Datums-String angegeben werden. Eine Umwandlung mit der Funktion CDate() ist nicht möglich!

Const dteEstablished As Date = "1984-03-01" 
Const dteIncorporated As Date = 36742

Datentypen

Da Konstanten ausschließlich bei der Deklaration den gewünschten Wert erhalten können, können sie ausschließlich natürliche Datentypen enthalten, also keine (Klassen-)Objekte, Types, Collections oder Arrays.

Eine vollständige Liste der in VBA verwendeten Datentypen finden Sie hier: Datentypen

Geltungsbereich und Lebensdauer

Geltungsbereich und Lebensdauer sind identisch zu den bei Variablen beschriebenen Geltungsbereichen und Lebensdauern. Das Schlüsselwort Static ist jedoch nicht zulässig.