(ganz) kurze Einführung in die Klassenprogrammierung

Andre Schau (schauan) im September 2012

Klassen sind auf den ersten Blick eine eigene Form von Modulen. Beim Einfügen eines Klassenmoduls erhalte ich im Projektexplorer einen neue Gruppe, ähnlich wie beim Einfügen von Modulen oder Userforms. Für die Programmierung wird ein Modulblatt bereitgestellt. Ähnlich wie in den Tabellenblattmodulen oder in DieseArbeitsmappe ist die Auswahl oben bereits vorbelegt, links mit Class und rechts mit Initialize und Terminate. Initialize und Terminate sind dem einen oder anderen viellecht schon vom Userform bekannt und haben eine vergleichbare Funktion. Für unsere kleine Einführung benötigen wir beides jedoch nicht. Klassen kann man mit Objekten vergleichen. Sie besitzen ebenso Eigenschaften und Methoden und können auf Ereignisse reagieren.

Ich werfe hier mal ein paar Fachbegriffe in den Raum, die der unbedarfte Leser am Besten überspringt - sie werden für die (ganz) kurze Einführung nicht benötigt. Eigenschaften werden in Variablen der Klassenmodule hinterlegt, die über Properties zu belegen sind. Für Methoden und Aktionen innerhalb der Klassen nutzt man Sub's und Funktionen, und Ereignisse können von der Application oder dem jeweiligen Objekt über WithEvents abgegriffen werden, oder man programmiert in sogenannten RaiseEvents eigene. Aber das möchte ich, wie gesagt, in diesem Beispiel nicht vertiefen - ausgenommen die Ereignisse von Steuerelementen.

Tabellenblattauswahl Was möchte ich nun zum Ziel setzen? Oft wird in Foren nach einer Übersicht von Tabellenblättern gefragt, die möglichst auch eine Auswahl für ein zu aktivierendes Blatt bietet. Wir werden das mit einem Userform lösen.

##################################################
**************************************************
Datei UserformButtons.xlsm (ab 2007)

Benötigt werden
1 kleines userform
ShowModal sollte auf False stehen, damit man später auch in den Blättern etwas tun kann.
1 kleiner Rahmen
Die Höhe ist unerheblich, wir wissen ja nicht, wie viele Blätter auf uns zukommen. Zwei Optionbuttons sollten drauf passen, breit genug, um die Tabellenblattnamen auszugeben. Alles weitere lösen wir programmtechnisch.

optional
1 Button OK
1 Button Abbrechen

**************************************************
So, um die Auswahl der Blätter vorzunehmen, wären Radiobuttons bzw. Optionbuttons von Vorteil. Bei diesen schaltet sich bei Aktivierung eines Buttons der vorher aktive deaktiv. Einfügen tun wir die in einer Schleife. Wir dimensionieren dazu am Anfang des Makros noch eine entsprechende Objektvariable.
codeauszug:

'Controls/OptionButton 
Dim ctrOBtn As MSForms.OptionButton

'Schleife ueber alle Tabellenblaetter 
For iCnt = 1 To Worksheets.Count
  'Optionbutton hinzufuegen und zuweisen 
  Set ctrOBtn = Me.Frame1.Controls.Add("Forms.OptionButton.1", "wsho" & iCnt, True)
  '************************************************** 
  'Was fehlt noch? Die Positionierung. 
  'mit dem Optionbutton 
  With ctrOBtn
    'Hoehe einstellen 
    .Height = 14.75
    'Breite einstellen 
    .Width = 55
    'Oben einstellen 
    .Top = 10 + 22 * (iCnt - 1)
    'links einstellen 
    .Left = 5
    'Beschreibung = Blattname 
    .Caption = Worksheets(iCnt).Name
    'waehlbar = Blatt sichtbar? 
    .Enabled = Worksheets(s).Visible
    'Wenn Blattnamme = Name des aktiven Blattes dann 
    If CBool(Worksheets(iCnt).Name = ActiveSheet.Name) = True Then
      'Button = true 
      .Value = True
    'Ende Wenn Blattnamme = Name des aktiven Blattes dann 
    End If
  'Ende mit dem Optionbutton 
  End With
  
Next

**************************************************
So, jetzt stehen die Buttons zwar alle schön untereinander, man kommt aber nicht an alle ran. Was fehlt? Eine Scrollbar.
Da von vornherein nicht klar ist, ob der Platz im Rahmen für die Buttons reicht, sollte bei entsprechender Anzahl Buttons automatisch ein Scrollbalken erscheinen. Den entsprechenden code platzieren wir mit etwas Mathematik nach der Schleife.
codeauszug:

'Wenn Hoehe der Buttons groesser der Rahmenhoehe dann 
'Hinweis: iCnt am Schleifenende 1 mehr als Optionbuttons, daher - 1 
If 10 + 22 * (iCnt - 1) > Me.Frame1.Height Then
  'Scrollbar setzen wenn mehr Datenspalten im Report 
  'Scrollbar aktivieren 
  If Me.Frame1.ScrollBars = fmScrollBarsNone Then _
     Me.Frame1.ScrollBars = fmScrollBarsVertical
  'Groesse der Scrollbar einstellen 
  If Me.Frame1.ScrollBars = fmScrollBarsVertical Then _
     Me.Frame1.ScrollHeight = 10 + 23 * iCnt
'Ende Wenn Hoehe der Buttons groesser der Rahmenhoehe dann 
End If

Beim Test ist noch nichts weiter passiert? Beim Drücken auf die Buttons sollte auch noch nichts passieren ...

##################################################
**************************************************
Bevor wir zu den Klassen gehen, kommen noch ein paar kleine Änderungen ..

Datei UserformButtonsCls000.xlsm

Einiges gefällt mir noch nicht. Die Variablen sind nicht aussagekräftig und nicht dimensioniert. Kommentare für's Verständnis fehlen.

Hinweise:
Man könnte (und sollte) einiges mehr tun. Die Beschriftung vom Userform kann einen Namen erhalten, z.B. "Tabellenauswahl".
Userform und Commandbuttons können, wie bei den Variablen angewendet, ebenfalls aussagekräftige Namen bekommen, z.B. cBtnOK ...

##################################################
**************************************************
So, jetzt geht es mit den Klassen los.

Datei UserformButtonsCls001.xlsm

Wir fügen ein neues Klassenmodul ein und benennen es

clsButtonEvents

Wir wollen mit dem Event von Buttons arbeiten und bei anklicken oder beim Ändern eine Aktion auslösen. Wir holen also die Ereignisse - WithEvents - der Option- Buttons. ALs Bezeichner nehmen wir Button - man kann aber auch andere Namen wählen.
codeauszug:

Public WithEvents Button As MSForms.OptionButton

Dann fügen wir eine Aktion ein - hier das Change-Ereignis. Das geht genau so wie man es vielleicht von einem "normalen" OptionButton_Change - Ereignis kennt.
codeauszug:

Private Sub Button_Change()
'   MsgBox "2 - Change" & vbLf & Button.Value & vbTab & Button.Caption 
   Sheets(Button.Caption).Activate
End Sub

**************************************************
Im Userform Modul ist etwas mehr einzufügen. Hier ganz kurz in einem Satz - Erklärungen im folgenden Text.
Der Button wird der Klasse zugewiesen, das Ereignis wird definiert, und in einer Collection mit den anderen Buttons "gesammelt".

Was hat es mit der Collection auf sich?

Wir benötigen eine globale Variable bzw. eine Collection, in der wir die Buttons makroübergreifend erfassen. Eine Collection hat gegenüber einem Array u.a. den Vorteil, dass keine Dimensionierung benötigt wird und das Objekte - für unser Beispiel die Optionbuttons - hinterlegt werden können. Der Name ist hier wieder frei wählbar. Excel erkennt, dass die Buttons "irgendwo" vorliegen.

Dim colBtn As Collection 'Button-Collection

Im Userform_Initialize müssen wir noch die Klasse dimensionieren. Dazu ist der Name des Klassenmodus zu verwenden
codeauszug:

'Klasse 
Dim ButtonEvent As clsButtonEvents

**************************************************
Anschließend müssen wir die 3 Dinge auch zuweisen. Die Collection vor der Schleife, ...
codeauszug:

'Collection zuweisen 
Set colBtn = New Collection

'Button der Klasse zuweisen 
Set ButtonEvent = New clsButtonEvents
'Change-Event zuweisen 
Set ButtonEvent.Button = ctrOBtn

**************************************************
... und letztendlich den Button der Collection hinzufügen.
codeauszug:

colBtn.Add ButtonEvent

So, jetzt sollten die Blätter auch gewechselt werden.

##################################################
**************************************************
Übrigens kann man den Buttons auch unterschiedliche Aktionen beim gleichen Ereigniss zuweisen.

Datei UserformButtonsCls002.xlsm

zusätzlicher Code im Klassenmodul
codeauszug:

Private Sub btnSpecialEve_Change()
   MsgBox "1 - Special Change" & vbLf & Button.Value & vbTab & Button.Caption
End Sub

Das zusätzliche Ereignis ist natürlich auch im code des Userform dem Button zusätzlich zuzuweisen.
codeauszug:

'Hinweis: 
'Reihenfolge der Ausfuehrung Change - SpecialChange 
'entsprechend der Reihenfolge der Zuweisung hier 
'Special-Event zuweisen 
Set ButtonEvent.btnSpecialEve = ctrOBtn

Man könnte auf diese Weise z.B. verschiedene Ereignissse an verschiedene Buttons zuweisen.

##################################################
**************************************************
Im Beispiel ist ein ausgeblendetes Blatt dabei. Jetzt wäre noch eine Möglichkeit zum Einblenden erwünscht.

Datei UserformButtonsCls003.xlsm

Statt Optionbuttons sind hier Checkboxen angebracht. Diese legen wir nach dem gleichen Prinzip wie die Buttons an. Dazu kopieren wir einfach die codepassagen der Buttons, legen ein entsprechendes Klassenmodul an, ändern Buttons in Boxen ..

Übrigens ist der jeweilige Tabellenblattname in der Eigenschaft "Tag" der CheckBoxen versteckt. Zum einen steht der Name schon in der Beschriftung der OptionButtons, zum anderen ist es für den Anwender auch nicht verkehrt, wenn er lesen kann, was die Checkbox bewirkt ...

Datei UserformButtonsCls004.xlsm

... und erweitern dann den code im Klassenmodul für das Ein- und Ausbenden der Blätter anhand dem Wahrheitswert der Checkbuttons.

Na, das war doch gar nicht so schwer. Die Commandbuttons haben wir eigentlich nicht gebraucht - die könnten entfallen. Es ist hier einfacher, die Aktionen unmittelbar bei Klick auf die Optionbuttons und Checkboxen auszuführen, als extra noch OK abzuwarten. Abbrechen kann man auch über das X vom Userform ....
Hinweis:
Die OptionButtons sind hier alle wählbar gesetz. Man könnte in Abhängigkeit der Sichtbarkeit der Blätter und der Aktion der CheckBoxen die Wählbarkeit steuern.

##################################################
Weiteres Beispiel:
Datei Logfile.xls

Eine andere Frage betrifft die Auslösung eines Ereignisses bei jedem Öffnen von beliebigen Exceldateien. Mit der Beispieldatei kann man ein Ereignis beim Öffnen jeglicher Excel-Mappen auslösen. Ich habe es zur Protokollierung von Dateizugriffen genutzt. Es wird ein Logdatei erzeugt. Wo, kann man auf dem Tabellenbatt angeben. Das sollte man aber nicht zur Überwachung von Mitarbeiteraktivitäten einsetzen - es wäre nicht die erste Affäre mit folgender negativer Publicity dieser Art.

Online-Literatur:

deutsch

online-excel.de

vba-wordwelt.de

office-loesung.de

de.wikibooks.org

coberweis.de (Download ppt)

englisch

cpearson.com

di-mgt.com.au


VBA Kurztutorial

dokumente.unibw.de (Dowmnload pdf)