Lies in den Artikel rein und unten bekommst Du ein unschlagbares Angebot!
Im Artikel “Menüs per VBA programmieren” (www.vbentwickler.de/435) haben wir uns bereits angesehen, wie wir die Menüstruktur selbst im VBA-Editor per VBA programmieren können. Damit wissen wir nun, wie wir Hauptmenüleisten, Symbolleisten und Kontextmenüs erstellen und anzeigen können. Es fehlt allerdings noch das Salz in der Suppe, nämlich die Steuerelemente auf diesen Menüs. Welche es gibt und wie man diese hinzufügt und mit Aktionen versieht, schauen wir uns in diesem Artikel an.
Wer den VBA-Editor mit eigenen Funktionen erweitern will und das beispielsweise mit COM-Add-Ins auf Basis von twinBASIC realisiert, möchte die hinzugefügten Funktionen auch auf irgendeine Weise für den Benutzer zugänglich machen. Dazu bietet sich das Menüsystem an. Damit können wir in der Menüleiste, den Symbolleisten und in Kontextmenüs Befehle zum Aufrufen der benutzerdefinierten Funktionen hinzufügen. Allerdings brauchen wir hier nicht nur die entsprechenden Elemente, sondern wir müssen auch noch Steuerelemente hinzufügen. Dies werden meist einfache Schaltflächen sein. Wir schauen uns allerdings in diesem Artikel alle der wenigen verfügbaren Steuerelemente für die Menüs des VBA-Editors an.
Steuerelemente des CommandBar-Elements
Dem CommandBar-Element können wir die folgenden Steuerelemente hinzufügen:
- Schaltfläche (msoControlButton)
- Auswahlfeld (msoControlComboBox)
- Untermenü (msoControlPopup)
Um ein solches Steuerelement hinzuzufügen, verwenden wir die Add-Methode der Controls-Auflistung des CommandBar-Objekts. Das folgende, einfache Beispiel fügt einfach jeweils ein Element des jeweiligen Typs zu einer neu erstellten Symbolleiste hinzu:
Public Sub AddControls() Dim cbr As CommandBar Dim cbb As CommandBarButton Dim cbc As CommandBarComboBox Dim cbp As CommandBarPopup On Error Resume Next VBE.CommandBars("Symbolleiste mit Controls").Delete On Error GoTo 0 Set cbr = VBE.CommandBars.Add( _ "Symbolleiste mit Controls") With cbr Set cbb = cbr.Controls.Add(msoControlButton) With cbb .Caption = "Button" .Style = msoButtonCaption End With Set cbc = cbr.Controls.Add(msoControlComboBox) With cbc .Caption = "ComboBox" End With Set cbp = cbr.Controls.Add(msoControlPopup) With cbp .Caption = "Popup" End With .Visible = True End With End Sub
Die Prozedur löscht zunächst eine gegebenenfalls bereits von einem vorherigen Test vorhandene Symbolleiste namens Symbolleiste mit Controls aus der CommandBars-Auflistung. Für den Fall, dass dieses noch nicht angelegt oder zuvor auf andere Art und Weise gelöscht wurde, deaktivieren wir die eingebaute Fehlerbehandlung, damit dann kein Fehler ausgelöst wird.
Dann legt sie ein neues CommandBar-Objekt mit diesem Namen an. Anschließend fügen wir mit der Add-Methode der Controls-Auflistung zunächst eine Schaltfläche mit dem Typ msoControlButton an und stellen dafür die Beschriftung ein. Damit diese auch erscheint, legen wir die Eigenschaft Style auf den Wert msoButtonCaption fest.
Danach legt die Prozedur ein Auswahlfeld an und verwendet dazu den Typ msoControlComboBox als ersten Parameter der Add-Methode. Diesem fügen wir auch gleich ein erstes Element hinzu.
Schließlich folgt noch ein Untermenü mit dem Typ msoControlPopup. Für dieses brauchen wir den Style nicht auf msoButtonCaption festzulegen, die Beschriftung wird automatisch angezeigt.
Das Ergebnis sehen wir in Bild 1.
Bild 1: Beispiel für Steuerelemente im CommandBar
Schaltflächen im CommandBar-Element
Nachdem wir eine Schaltfläche zu einem CommandBar-Element hinzufügt haben, ist erst einmal wichtig, dass wir dem Benutzer mitteilen, wozu er diese Schaltfläche verwenden kann. Dazu können wir primär Symbole und/oder Texte verwenden. Den Text stellen wir immer mit der Eigenschaft Caption ein. Damit die Beschriftung überhaupt sichtbar ist, müssen wir die Style-Eigenschaft auf den entsprechenden Wert einstellen. Dazu haben wir die folgenden Möglichkeiten:
- msoButtonCaption: Zeigt nur die Beschriftung an.
- msoButtonIcon: Zeigt nur ein Symbol an.
- msoButtonIconAndCaption: Zeigt Symbol und Text an.
Ereignisse von Schaltflächen programmieren
Wer bereits einmal Menüleisten für die verschiedenen Office-Anwendungen mit der Version 2003 und älter programmiert hat oder auch Kontextmenüs für die aktuellen Versionen, der kennt die OnAction-Eigenschaft. Für diese Eigenschaft eines CommandBarButton-Objekts hinterlegt man den Namen einer öffentlichen VBA-Prozedur, die durch das Anklicken des Menüpunktes ausgelöst werden soll.
Dies funktioniert bei der Programmierung von Menüs für den VBA-Editor so nicht mehr. Hier müssen wir ein Ereignis programmieren. Leider können wir Ereignisse nur innerhalb von Klassenmodulen implementieren und nicht in Standardmodulen. Wir benötigen also eine Klasse, die einen Verweis auf unser CommandBarButton-Objekt enthält und in der wir die Ereignisprozedur implementieren.
Diese Klasse heißt clsCommandBarButton und sieht wie in Listing 1 aus. Hier definieren wir als Erstes eine Objektvariable, mit der wir das CommandBarButton-Objekt referenzieren wollen. Wir fügen der Deklaration das Schlüsselwort WithEvents hinzu, damit wir die Ereignisse dieses Objekts innerhalb der aktuellen Klasse implementieren können.
Private WithEvents m_CommandBarButton As CommandBarButton Public Property Set CommandBarButton(cbb As CommandBarButton) Set m_CommandBarButton = cbb End Property Public Property Get CommandBarButton() As CommandBarButton Set CommandBarButton = m_CommandBarButton End Property Private Sub m_CommandBarButton_Click(ByVal Ctrl As Office.CommandBarButton, CancelDefault As Boolean) MsgBox "CommandBarButton ''" & m_CommandBarButton.Caption & "'' angeklickt." End Sub
Listing 1: Klassenmodul für die Ereignisse von CommandBarButton-Ereignissen
Damit wir von außen einen Verweis auf das CommandBarButton-Objekt übergeben können, für das wir das Ereignis implementieren wollen, fügen wir eine Property Set-Methode hinzu. Diese nimmt einen Verweis auf das CommandBarButton-Element entgegen. Außerdem fügen wir noch eine Property Get-Prozedur hinzu, mit der wir den Verweis auf dieses Steuerelement abfragen können.
Um schließlich die Ereignisprozedur zu implementieren, wählen wir im linken Kombinationsfeld des Codefensters den Eintrag m_CommandBarButton aus und den dann im rechten Fenster erscheinenden Eintrag Click (siehe Bild 2). Dies legt die Ereignisprozedur m_CommandBarButton_Click an, der wir im Beispiel einfach eine Meldungsfenster-Funktion hinzugefügt haben.
Bild 2: Anlegen der Ereignisprozedur für das Click-Ereignis
Nun müssen wir noch das CommandBarButton-Objekt in einem Menü anzeigen, eine neue Instanz der Klasse clsCommandBarButton erzeugen und schließlich das Menü mit der Schaltfläche anzeigen.
Um zu verhindern, dass die Instanz der Klasse clsCommandBarButton nach dem Durchlaufen der Prozedur zum Erstellen der CommandBar mit dem CommandBarButton verloren geht, weil wir die mit einer Variablen innerhalb der Prozedur referenziert haben, verschieben wir diese Deklaration mit der folgende Anweisung nach außen (siehe Modul mdlCommandBarButtonMitEvent):
Dim objCommandBarButton As clsCommandBarButton
Die Prozedur selbst findest Du in Listing 2.
Dim objCommandBarButton As clsCommandBarButton Public Sub CommandBarButtonMitEvent() Dim cbr As CommandBar Dim cbb As CommandBarButton On Error Resume Next VBE.CommandBars("CommandBarButtonMitEvent").Delete On Error GoTo 0 Set cbr = VBE.CommandBars.Add("CommandBarButtonMitEvent") With cbr Set cbb = cbr.Controls.Add(msoControlButton) With cbb .Style = msoButtonCaption .Caption = "Button mit Ereignis" End With Set objCommandBarButton = New clsCommandBarButton Set objCommandBarButton.CommandBarButton = cbb End With cbr.Visible = True End Sub
Listing 2: Anlegen eines CommandBarButtons mit Ereignis
Diese deklariert ein CommandBar– und ein CommandBarButton-Element. Dann löscht sie eine eventuell bereits unter dem Namen CommandBarButtonMitEvent vorhandene Menüleiste und legt diese erneut an. Dann fügt sie mit der Add-Methode der Controls-Auflistung ein neues CommandBarButton-Element hinzu und stellt den Stil und die Beschriftung des Steuerelements ein.
Dann folgen die für die Ereignisprozedur wichtigen Schritte: Wir legen ein neues Objekt auf Basis der Klasse clsCommandBarButton an und weisen der Eigenschaft CommandBarButton einen Verweis auf das soeben erstellte CommandBarButton-Objekt zu. Schließlich blenden wir das Menü noch ein.
Klicken wir danach auf das einzige Steuerelement, erscheint die gewünschte Meldungsbox (siehe Bild 3).
Bild 3: Menü mit CommandBarButton und Ereignis
Symbole in Schaltflächen
Während wir den Text auf einfache Weise mit der Caption-Eigenschaft zuweisen können, sieht das bei Symbolen schon anders aus. Hier haben wir grundsätzlich zwei Möglichkeiten:
- Wir fügen eines der bereits vorhandenen Symbole hinzu, also eines der für die übrigen Steuerelemente verfügbaren oder
- wir fügen ein Bild im Format StdPicture über die Eigenschaft Picture hinzu.
Eingebaute Symbole hinzufügen
Der Einbau eingebauter Symbole ist etwas einfacher, weil wir keinen eigenen VBA-Code benötigen, um erst vorhandene Dateien in StdPicture-Objekte umwandeln zu müssen. Allerdings macht es dann Sinn, sich gut mit den eingebauten Symbolen auszukennen. Die eingebauten Symbole haben jeweils eine eindeutige Nummer, die wir über die Eigenschaft FaceId ermitteln können. Was wir also brauchen, ist eine Übersicht aller Icons mit den jeweiligen Werten für die Eigenschaft FaceId. Diese erhalten wir am einfachsten, indem wir eine neue Symbolleiste erstellen, der wir alle Symbole der eingebauten Schaltflächen hinzufügen.
Dies erledigen wir in der Prozedur AlleEingebautenIcons aus Listing 3.
Public Sub AlleEingebautenIconsNachID() Dim cbr As CommandBar Dim cbb As CommandBarButton Dim l As Long Dim objCommandBarButton As clsCommandBarButtonFaceID Set colCommandBarButtons = New Collection On Error Resume Next VBE.CommandBars("AlleIcons").Delete On Error GoTo 0 Set cbr = VBE.CommandBars.Add("AlleIcons") With cbr For l = 1 To 6000 If IsNull(DLookup("FaceID", "tblEmptyFaceIDs", "FaceID = " & l)) Then Set cbb = cbr.Controls.Add(msoControlButton) With cbb .FaceId = l .TooltipText = l .Tag = l End With Set objCommandBarButton = New clsCommandBarButtonFaceID Set objCommandBarButton.CommandBarButton = cbb colCommandBarButtons.Add objCommandBarButton End If Next l End With cbr.Visible = True End Sub
Listing 3: Funktion zum Schreiben aller Icons in eine Symbolleiste
Hier finden wir gleich ein spannendes Beispiel für den Fall, dass wir viele Steuerelemente in einer Menüleiste mit einem Ereignis ausstatten wollen, das beim Anklicken die gleiche Funktion ausführen soll – gegebenenfalls noch mit kleinen Varianten durch spezielle Eigenschaften des CommandBarButton-Elements.
Grundlage für diese Prozedur ist, dass es FaceId-Werte gibt, die bis 6.000 reichen. Wir wollen all diese Werte einmal durchlaufen und in ein einziges CommandBar-Objekt schreiben. Allerdings liefern nicht alle Werte von FaceId tatsächlich ein Symbol. Deshalb wollen wir diejenigen, für die kein Symbol hinterlegt ist, auch nicht in das Menü aufnehmen. Daher haben wir – wir probieren dies hier in einer Access-Datenbank aus – eine Tabelle angelegt, in welcher wir die FaceId-Werte speichern, die kein Symbol enthalten (wir hätten das auch andersherum machen können, haben uns aber für diese Variante entschieden).
Um die Steuerelemente ohne Symbol für die FaceId in die Tabelle tblEmptyFaceIds zu schreiben, haben wir wiederum eine Klasse mit einer Ereignisprozedur angelegt. Diese ist grundsätzlich genauso aufgebaut wie die zuvor beschriebene Klasse clsCommandBarButton.
Sie heißt jedoch clsCommandBarButtonFaceID und enthält die folgende Ereignisprozedur:
Private Sub m_CommandBarButton_Click(ByVal Ctrl As _ Office.CommandBarButton, CancelDefault As Boolean) CurrentDb.Execute "INSERT INTO " _ & "tblEmptyFaceIDs(FaceID) VALUES(" _ & m_CommandBarButton.Tag & ")", dbFailOnError End Sub
Diese trägt einen neuen Datensatz mit der FaceId in die Tabelle tblEmptyFaceIDs ein.
Diese Klasse deklarieren wir nun innerhalb der Prozedur und nicht außerhalb wie im vorherigen Beispiel. Warum das? Weil wir mehr als eine Instanz dieser Klasse anlegen – genau genommen zunächst einmal 6.000 Stück. Und da wir keine 6.000 Variablen deklarieren wollen, deklarieren wir nur eine temporäre. Die erzeugten Objekte fügen wir dann einer Collection hinzu, die wir wie folgt im Kopf des Standardmoduls deklarieren:
Public colCommandBarButtons As Collection
Die Collection initialisieren wir im nächsten Schritt. Dann löschen wir das Menü namens AlleIcons vorsichtshalber, um es im nächsten Schritt gleich wieder anzulegen. Dann durchlaufen wir in einer Schleife die Werte von 1 bis 6.000 und prüfen zunächst per DLookup, ob die FaceId nicht leer ist und bereits in der Tabelle tblEmptyFaceIDs eingetragen ist. Ist das nicht der Fall, legen wir ein neues CommandBarButton-Element an und stellen die Eigenschaft FaceId auf den aktuellen Wert der Laufvariablen l ein. Außerdem legen wir den ToolTipText und die Eigenschaft Tag auf den Wert dieser Variablen fest.
Schließlich legen wir ein neues Objekt der Klasse clsCommandBarButtonFaceIdD an und weisen seiner Eigenschaft CommandBarButton die Schaltfläche aus cbb zu. Diese Objektvariable fügen wir dann mit der Add-Methode der Collection colCommandBarButtons zu.