Variablen: Unterschied zwischen den Versionen

Aus VBA-wiki
Zur Navigation springen Zur Suche springen
Zeile 227: Zeile 227:
==== Projektweite Variablen ====
==== 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 <code>Public</code>: 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.
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 <code>Public</code>:  
 
<span style="Color:blue">Option Explicit </span>
<span style="Color:blue">
Public </span>Variable<span style="Color:blue"> As String </span>
 
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 ====
==== Besondere Geltungsbereiche in Klassen und UserFormen ====

Version vom 19. Dezember 2018, 16:07 Uhr

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) Private Sub ListOfParameters(ByVal lngValue As Long, ByVal strValue As String, ByVal dteDate As Date)

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. 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. Private Sub OptionalParameter(ByVal strNecessary As String, Optional 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) Der Aufruf kann nun wie folgt durchgeführt werden: OptionalParameter "Hallo" oder mit zweitem Parameter OptionalParameter "Hallo", 7 ;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! Tipp: Wenn Sie prüfen möchten, ob ein optionaler Parameter angegeben wurde, belegen Sie ihn mit einem unwahrscheinlichen oder unmöglichen Wert: Public Function RandomDouble(ByVal dblBottom As Double, ByVal dblTop As Double, Optional ByVal lngRoundToDigits As Long = -1) As Double Hier wird der Standardwert für 'lngRoundToDigits' mit '-1' vorbelegt, denn ohne diese Angabe wäre dieser mit 0 belegt und das Ergebnis würde somit immer auf 0 Nachkommastellen gerundet. 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
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 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" 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 dteEstablished As Date = 30742

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.