Office Forum
www.Office-Loesung.de
Access :: Excel :: Outlook :: PowerPoint :: Word :: Office :: Wieder Online ---> provisorisches Office Forum <-
Konstanten und Enums-kleine Helfer für übersichtlichen Code
zurück: Datensatzmarkierer zum Ändern von Checkboxen verwenden weiter: Tile Horizontally/Vertically Unbeantwortete Beiträge anzeigen
Neues Thema eröffnen   Neue Antwort erstellen     Status: Tutorial Facebook-Likes Diese Seite Freunden empfehlen
Zu Browser-Favoriten hinzufügen
Autor Nachricht
Bitsqueezer
Office-VBA-Programmierer


Verfasst am:
29. Sep 2010, 23:11
Rufname:

Konstanten und Enums-kleine Helfer für übersichtlichen Code - Konstanten und Enums-kleine Helfer für übersichtlichen Code

Nach oben
       Version: (keine Angabe möglich)

Hallo zusammen,

wohl einige haben schon ein VBA-Konstrukt angewendet, um numerische Konstanten zu definieren, daß sich "Enum" (Enumeration = Aufzählung) nennt. Hier mal ein paar Anregungen, wie man Enums sinnvoll einsetzen kann.

Wenn man im Code z.B. globale Konstanten benötigt, schreibt man in ein Standardmodul zum Beispiel:
Code:
Public Const cApfel As String = "Apfel"
Public Const cBirne As String = "Birne"
Public Const cBanane As String = "Banane"
Public Const cOrange As String = "Orange"
Im Code, wo man diese verwenden möchte, schreibt man dann z.B.:
Code:
    Select Case strFrucht
      Case cApfel
        '...
      Case cBirne
        '...
      Case cBanane
        '...
      Case cOrange
        '...
    End Select
IntelliSense sei Dank, findet man die Konstanten halbwegs gut in der Liste. (Schöner noch, wenn man sie mit dem gleichen Bezeichner einführt, zum Beispiel "cFRUCHT_Apfel", "c_FRUCHT_Banane" usw., da sie dann alle zusammenstehen.)

In dem Vergleich oben will man eine Stringvariable mit einem festen Text vergleichen, und so kann man aus der Birne im Standardmodul durch Änderung der Konstante einfach "Williams-Christ-Birne" machen, ohne daß der Code ansonsten geändert werden müßte. Wenn man das konsequent durchzieht, spart man sich später eine große Menge Änderungsarbeit, und der Code wird lesbarer, da man so ja sofort im Klartext lesen kann, was verglichen wird.

Wie ist es aber, wenn statt eines Strings eine Zahl verglichen werden soll (z.B. ein "Fruchtcode")?

Würde dann so aussehen:
Code:
Public Const cApfel As Integer = 1
Public Const cBirne As Integer = 2
Public Const cBanane As Integer = 3
Public Const cOrange As Integer = 4

    Select Case intFrucht
      Case cApfel
        '...
      Case cBirne
        '...
      Case cBanane
        '...
      Case cOrange
        '...
    End Select
Schön, der Code bleibt immer noch leserlich, und man muß gar nicht wissen, was hinter "intFrucht" steht - und sollte sich der Code ändern, müssen nur die Zahlen in den Konstanten geändert werden. Es fällt aber auch auf, daß der Code bis auf den Datentyp der Vergleichsvariable identisch ist. Außerdem könnte es ja an anderer Stelle eine weitere Liste von Konstanten geben, die vielleicht so aussieht:
Code:
Public Const cJohannisbeere As Integer = 1
Public Const cHimbeere As Integer = 2
Public Const cErdbeere As Integer = 3
Public Const cBlaubeere As Integer = 4
Wenn man das jetzt in IntelliSense liest, könnte man mit den Früchten oben schnell durcheinanderkommen, auch ein "cFRUCHT_" davor hilft da nicht weiter, sind ja alles Früchte. Müßte also jede wieder einen eigenen Prefix bekommen usw.

Aber für solche Fälle gibt es die Enums. Damit kann man Aufzählungen praktisch gruppieren, und sie dürfen ebenfalls Private oder Public deklariert werden. Allerdings sind sie beschränkt auf ganzzahlige Werte.

Die beiden Aufzählungen oben könnte man damit nun so schreiben:
Code:
Public Enum EnmFruechte
    Apfel = 1
    Birne = 2
    Banane = 3
    Orange = 4
End Enum

Public Enum EnmBeeren
    Johannisbeere = 1
    Himbeere = 2
    Erdbeere = 3
    Blaubeere = 4
End Enum
Im Code kann man nun auf die Enumeration zugreifen wie auf ein Objekt und IntelliSense zeigt dann nur noch die Liste der möglichen Konstanten dieser Aufzählung an:
Code:
    Select Case intFrucht
      Case EnmFruechte.Apfel
      Case EnmFruechte.Banane
      Case EnmFruechte.Birne
      Case EnmFruechte.Orange
    End Select
Mit dem Eingeben des "." wird dann die zugehörige Liste angezeigt.

Aber Enums können noch viel mehr. Zum einen, da sie Aufzählungen sind, benötigen sie keine Werte, man kann also auch einfach schreiben:
Code:
Public Enum EnmFruechte
    Apfel
    Birne
    Banane
    Orange
End Enum
Werte muß man nur vergeben, wenn man auch wirklich einen definitiven Wert in jeder Zeile benötigt, ansonsten numeriert VBA automatisch in der Reihenfolge, in der die Konstanten in der Enumeration auftauchen, von 1 bis zum letzten Element (in der Liste in IntelliSense werden sie automatisch alphabetisch sortiert, unabhängig von ihrer Position in der Enumeration, dort bestimmt die Position lediglich den späteren Wert). Der Vorteil: Wenn man später ein Element einfügen will und alle anderen sollen weiterhin durchnumeriert sein, müßte man bei einer festen Wertevergabe nun alle Werte selbst anpassen. So schreibt man einfach die neue Zeile hinein und fertig.

Das alleine würde eine Enum aber nicht so interessant machen, man kann das Spiel noch weitertreiben: Im Beispiel war eine Variable namens "intFrucht" als Integer dimensioniert. Man kann eine Variable aber auch als Enumeration dimensionieren. Also statt:
Code:
    Dim intFrucht As Integer
kann man auch schreiben:
Code:
    Dim intFrucht As EnmFruechte
Da Enumerations grundsätzlich immer ganzzahlige Werte haben, ist der Datentyp ein Integer - genau genommen ein Long Integer. Das kann man sich in VBA anzeigen lassen mit Debug.Print VarType(intFrucht) = vbLong, was True ergibt. Eine Enum könnte also theoretisch aus mehr als 2 Milliarden Einträgen bestehen....

Was daran besonders interessant ist, man kann nun dieser Variable eine Konstante direkt zuweisen. Wenn man tippt:
Code:
    intFrucht =
dann erscheint sofort die Liste der möglichen Konstanten, aus der man eine auswählen kann. So macht das Arbeiten mit Konstanten doch gleich viel mehr Spaß. Hier braucht man jetzt auch nicht "EnmFruechte.Apfel" zu schreiben, denn da der Datentyp auf diese Enumeration festgelegt ist, kann VBA eindeutig zuordnen, welche Konstante gemeint ist, selbst dann also, wenn "Apfel" nochmal in "EnmBeeren" auftauchen würde.

Entsprechend könnte auch der Select Case nun so gekürzt werden (wenngleich hier die Hilfe von IntelliSense nicht so toll ist):
Code:
    Select Case intFrucht
      Case Apfel
      Case Banane
      Case Birne
      Case Orange
    End Select
Kann man das noch verbessern? Aber klar. Die nächste Ebene der praktischen Enum-Anwendung sind der Anwendungszweck, wo man sie am allerbesten einsetzen kann: In Parametern von Subs/Functions. Da ja jetzt klar ist, daß man eine Variable auch als Enum deklarieren kann, kann man das natürlich auch in Parametern. Das sieht dann so aus:
Code:
Public Sub MeineSub(intFrucht As EnmFruechte)
    '...
End Sub
Das hat sowohl außerhalb der Sub wie innerhalb Auswirkungen. Schreibt man den Sub-Aufruf "MeineSub" und drückt die Leertaste, dann bekommt man nun gleich zwei Hilfen: Einmal die übliche gelbe Anzeige möglicher Parameter, in der der Datentyp ("EnmFruechte") mir gleich sagt, was hier gebraucht wird, andererseits aber praktischerweise auch gleich der Inhalt der Enum selbst, nämlich eine Auswahlliste der definierten Konstanten. So kann man nun bequem aussuchen, was man übergeben möchte - das kommt einem bekannt vor? Kein Wunder, denn VBA nutzt selbst diese Technik reichlich. Bekanntestes Beispiel ist die MsgBox: Wenn man
Code:
    MsgBox "Text",
tippt, erhält man als nächstes die Liste aller möglichen Messagebox-Styles, also welche Grafik angezeigt werden soll, welche Buttons usw. Und wenn man sich die gelbe Parameterinfo anschaut, steht da: "VbMsgBoxStyle". Und das ist die Enumeration. Die kann man sich auch ansehen, wenn man mit F2 in den Objektkatalog geht und in das untere Dropdownfeld "VbMsgBoxStyle" tippt und Enter drückt. Klickt man auf die einzelnen Elemente, sieht man unten, welcher Wert dahintersteht - das ist schon das ganze Geheimnis.

Wenn man das weiß, kann man nun bedeutend übersichtlicheren Code schreiben, da man in allen Fällen, wo ähnliche Auswertungen stattfinden, einfach eine Enumeration verwenden kann.

Bisher war es nur eine Public Sub in einem Standardmodul. Das funktioniert aber auch sehr praktisch in Klassenmodulen, die am meisten davon profitieren: Statt in irgendwelchen Standardmodulen verstreut definiert, kann man die Public Enum auch im Kopf eines Klassenmoduls definieren, womit diese dann nur für das jeweilige instantiierte Objekt gilt. So kann man also auch Parameter von Objektmethoden auf diese Weise komfortabler gestalten und gleichzeitig die Enums schön passend für das jeweilige Objekt definieren. Wieder ein Grund mehr, Klassenmodule den Standardmodulen vorzuziehen, wo immer möglich.

Moment, Klassenmodule...war da nicht noch was? Ach ja, Formulare und Reporte sind ja auch nichts anderes als Klassenmodule und können ebenso Public Subs enthalten oder Public Properties - und natürlich auch Public Enums... da kann man doch einiges draus machen...

Mit ein wenig Phantasie kann man aber auch Konstanten "variabel" halten, besonders mit Hilfe der Enums:
Code:
Public lngObst() As Long

Public Enum EnmAblage
    Schale
    Glas
    Teller
    Topf
End Enum

Public Enum EnmBaumObst
    Apfel = 10
    Banane = 20
    Birne = 30
    Orange = 40
End Enum

Public Enum EnmBeeren
    Johannisbeere = 100
    Himbeere = 200
    Erdbeere = 300
    Blaubeere = 1
End Enum

Public Enum EnmObstAuswahl
    BaumObst
    Beeren
End Enum

Public Sub ObstAuswahl(lngAuswahl As EnmObstAuswahl)
    ReDim lngObst(EnmAblage.Topf)

    If lngAuswahl = BaumObst Then
        lngObst(EnmAblage.Schale) = Apfel
        lngObst(EnmAblage.Glas) = Banane
        lngObst(EnmAblage.Teller) = Birne
        lngObst(EnmAblage.Topf) = Orange
      ElseIf lngAuswahl = Beeren Then
        lngObst(EnmAblage.Schale) = Johannisbeere
        lngObst(EnmAblage.Glas) = Himbeere
        lngObst(EnmAblage.Teller) = Erdbeere
        lngObst(EnmAblage.Topf) = Blaubeere
      Else
        MsgBox "Keine Auswahl!"
    End If
Debug.Print lngObst(EnmAblage.Schale)
Debug.Print lngObst(EnmAblage.Glas)
Debug.Print lngObst(EnmAblage.Teller)
Debug.Print lngObst(EnmAblage.Topf)
End Sub
Die Enum "Ablage" definiert hier das Array "lngObst". Man muß lediglich ein bißchen auf die Positionen aufpassen. Schale, Glas, Teller, Topf bekommen ja automatisch die Werte 1,2,3 und 4. Mit "ReDim" wird das Array auf den größten Wert in der Enum eingestellt: Dem Topf. Sollte dem je ein anderer Behälter folgen, muß in "ObstAuswahl" der ReDim an das jeweils letzte Element angepaßt werden.
Mit "EnmObstAuswahl" wird der Parameter, wie oben gezeigt, bestimmt und innerhalb der Prozedur kann man dann ebenfalls auf dessen Liste zugreifen. Hier habe ich absichtlich ein If-ElseIf-Konstrukt verwendet, da es hierbei volle IntelliSense-Unterstützung gibt.

Den beiden Enums "EnmBeeren" und "EnmBaumObst" sind diesmal wieder Werte zugeordnet, die irgendwie und unsortiert sein können. Über die Zuweisung in der Sub gibt es ja eine eindeutige Zuordnung und während VBA weiterhin fleißig mit den Zahlenwerten arbeitet, können wir Programmierer uns bequem zurücklehnen und fließende Texte im Code lesen. Wenn sich je der Wert der Johannesbeere von 100 auf 101 ändert, dann kann man den nun einfach an einer Stelle ändern - in der Enum-Definition. Der Rest des Codes braucht nie mehr geändert zu werden. Viel übersichtlicher kann man es sich kaum machen.

Leider funktionieren Enum-Elemente nicht zusammen mit "Array", auch wenn sie vom Typ Long Integer sind, wohingegen man "Array" mit einzelnen Konstanten verwenden kann, da man diese explizit als "Long" (in diesem Beispiel) deklarieren kann.

Das If-Elseif-Konstrukt oben müßte man genauer auch noch so schreiben:
Code:
    If lngAuswahl = BaumObst Then
        lngObst(EnmAblage.Schale) = EnmBaumObst.Apfel
        lngObst(EnmAblage.Glas) = EnmBaumObst.Banane
        lngObst(EnmAblage.Teller) = EnmBaumObst.Birne
        lngObst(EnmAblage.Topf) = EnmBaumObst.Orange
      ElseIf lngAuswahl = Beeren Then
        lngObst(EnmAblage.Schale) = EnmBeeren.Johannisbeere
        lngObst(EnmAblage.Glas) = EnmBeeren.Himbeere
        lngObst(EnmAblage.Teller) = EnmBeeren.Erdbeere
        lngObst(EnmAblage.Topf) = EnmBeeren.Blaubeere
      Else
        MsgBox "Keine Auswahl!"
   End If
was es zum einen lesbarer macht und zum anderen sicherer. Denn da "lngObst" nicht als Enum deklariert ist wie der Parameter "lngAuswahl", sondern als ganz normaler "Long"-Wert, kann VBA hier keine Zuordnung zur richtigen Enumeration herausfinden. Im Beispiel gibt es keine Überschneidungen, daher funktioniert auch die Schreibweise oben. Da man das aber nie sicher voraussetzen kann, sollte man in allen Fällen, in denen VBA nicht selbst eine Liste aus der Enumeration mit IntelliSense generiert, sicherheitshalber den Namen der Enumeration und einen Punkt davorschreiben - und durch den Punkt wird einem die Liste dann ja auch wieder angezeigt, was es auch einfacher in der Eingabe macht.

Viel Spaß beim Experimentieren mit Enums...

Christian

PS.: Es soll auch nicht unerwähnt bleiben, daß Enums in VBA einen Bug kreieren können: Manchmal funktioniert "Debug-Compile" bei Verwendung einer Enum einfach nicht, es wird behauptet, der Typ sei nicht deklariert oder ähnliches, obwohl er deklariert ist und auch als Public gekennzeichnet. Einerseits sollte man dann einfach mal Access neu starten (da Änderungen in Enums bewirken, daß die alten Einträge dort immer noch in IntelliSense gelistet werden), andererseits hilft ein kleiner Workaround: Einfach mal in einer beliebigen Enum ein Zeichen im Enum-Namen einfügen, die Zeile verlassen und wieder zurück ändern. Dadurch wird die Liste neu generiert und i.d.R. klappt danach auch wieder "Debug-Compile" ohne Probleme.
Willi Wipp
Moderator


Verfasst am:
09. Apr 2011, 07:24
Rufname:
Wohnort: Raum Wiesbaden


AW: Konstanten und Enums-kleine Helfer für übersichtlichen C - AW: Konstanten und Enums-kleine Helfer für übersichtlichen C

Nach oben
       Version: (keine Angabe möglich)

{Dieser Beitrag nimmt das Thema aus den unbeantworteten Themen heraus}
Neues Thema eröffnen   Neue Antwort erstellen Alle Zeiten sind
GMT + 1 Stunde

Diese Seite Freunden empfehlen

Seite 1 von 1
Gehe zu:  
Du kannst Beiträge in dieses Forum schreiben.
Du kannst auf Beiträge in diesem Forum antworten.
Du kannst deine Beiträge in diesem Forum nicht bearbeiten.
Du kannst deine Beiträge in diesem Forum nicht löschen.
Du kannst an Umfragen in diesem Forum nicht mitmachen.
Du kannst Dateien in diesem Forum nicht posten
Du kannst Dateien in diesem Forum herunterladen

Verwandte Themen
Forum / Themen   Antworten   Autor   Aufrufe   Letzter Beitrag 
Keine neuen Beiträge Access Tabellen & Abfragen: SQL Code verschachteln 5 littlejohn 421 01. Okt 2012, 09:40
KlausMz SQL Code verschachteln
Keine neuen Beiträge Access Tabellen & Abfragen: Warum ändert Access den sql code? 12 abraxa 704 19. Jul 2009, 20:55
abraxa Warum ändert Access den sql code?
Keine neuen Beiträge Access Tabellen & Abfragen: Darstellungsart "Kontrollkästchen" per Code setzen 3 fragerer 285 13. März 2009, 16:32
Gast Darstellungsart "Kontrollkästchen" per Code setzen
Keine neuen Beiträge Access Tabellen & Abfragen: Button VBA Code zum Verknüpfen aller ODBC -Tabellen 3 adamth 3953 08. Sep 2008, 13:10
rita2008 Button VBA Code zum Verknüpfen aller ODBC -Tabellen
Keine neuen Beiträge Access Tabellen & Abfragen: VBA Code zum löschen leerer Datensätze 2 adamth 1124 31. Jul 2008, 20:44
adamth VBA Code zum löschen leerer Datensätze
Keine neuen Beiträge Access Tabellen & Abfragen: schnelle komplexe Abfrage per Code? 4 SaschaR 586 25. März 2008, 15:57
SaschaR schnelle komplexe Abfrage per Code?
Keine neuen Beiträge Access Tabellen & Abfragen: DateDiff in VBA Code berechnet liefert Nonsens 8 Utali 1324 15. Jan 2007, 17:08
Gast DateDiff in VBA Code berechnet liefert Nonsens
Keine neuen Beiträge Access Tabellen & Abfragen: Access Höhe eines Rechteck per VBA Code regulieren 2 Gast1 1835 30. Dez 2006, 16:13
Gast Access Höhe eines Rechteck per VBA Code regulieren
Keine neuen Beiträge Access Tabellen & Abfragen: ACCESS Splash - INSERT INTO Abfrage Code 0 Joppel 698 21. Dez 2006, 21:38
Joppel ACCESS Splash - INSERT INTO Abfrage Code
Keine neuen Beiträge Access Formulare: VBA Code 7 kiter 789 16. Okt 2006, 12:36
jens05 VBA Code
Keine neuen Beiträge Access Formulare: Textfelder per Code füllen. Formular hüpft wegen Focus .. 2 florenziger 1190 06. Okt 2006, 08:46
Gast Textfelder per Code füllen. Formular hüpft wegen Focus ..
Keine neuen Beiträge Access Formulare: Registersteuerelement + Code MouseMove 0 Borschtel 588 29. Sep 2006, 11:12
Borschtel Registersteuerelement + Code MouseMove
 

----> Diese Seite Freunden empfehlen <------ Impressum - Besuchen Sie auch: Microsoft-Excel Diagramme