Kontextmenüs per VBA programmieren

Vor sehr langer Zeit (2003) gab es für die Office-Anwendungen noch die Möglichkeit, Menüleisten, Symbolleisten und Kontextmenüs über die Benutzeroberfläche anzupassen. Die Menüleisten und Symbolleisten sind seit der Version 2007 Geschichte, und damit ist auch der Editor für die Gestaltung dieser Elemente verschwunden. Allerdings gibt es noch die Kontextmenüs, und diese lassen sich auch noch anpassen – zum Beispiel, um eigene Befehle hinzuzufügen. Diese könnten beispielsweise Teil von Add-Ins, COM-Add-Ins oder auch von Dokumenten sein. In diesem Artikel zeigen wir, wie man vorhandene Kontextmenüs bearbeitet oder eigene Kontextmenüs anlegt und diese bei Bedarf aufruft.

Unterschiede zwischen Outlook und den übrigen Office-Anwendungen

Zwischen Outlook und den übrigen Office-Anwendungen gibt es einen entscheidenden Unterschied für die individuelle Anpassungen von Kontextmenüs: Während wir unter Word, Excel, Access oder PowerPoint das Objektmodell aus der Bibliothek Microsoft Office x.0 Object Library nutzen können, um die gewünschten Anpassungen vorzunehmen, ist dies in Outlook nicht möglich. Hier sind die Kontextmenüs bereits Bestandteil des Ribbons. Änderungen der Kontextmenüs müssen wir in Outlook daher über die Ribbondefinition vornehmen, und zwar über die Einträge im Unterelement contextMenus. Dieses Thema behandeln wir im vorliegenden Artikel nicht, aber wir gehen im Detail darauf in einem weiteren Artikel namens Kontextmenüs in Outlook anpassen (www.vbentwickler.de/369) ein.

Beispieldateien

Da die CommandBars sich in den verschiedenen Office-Anwendungen Access, Excel und Word leicht unterschiedlich verhalten, haben wir jeweils eine Beispieldatei für jede Anwendung bereitgestellt:

  • Access: KontextmenuesPerVBA.accdb
  • Excel: KontextmenuesPerVBA.xlsm
  • Word: KontextmenuesPerVBA.docm

Objektmodell verfügbar machen

Um die Kontextmenüs anzupassen, benötigen wir Elemente der Bibliothek Microsoft Office x.0 Object Library. Diese ist in beispielsweise in den VBA-Projekten von Word und Excel bereits referenziert, nicht jedoch unter Access oder in anderen Projekten auf Basis von Visual Studio oder twinBASIC. Damit wir die Bibliothek etwa in Access unter Einsatz von IntelliSense nutzen können, fügen wir einen Verweis auf diese Bibliothek hinzu. Dazu öffnen wir zunächst den VBA-Editor der jeweiligen Anwendung, beispielsweise mit der Tastenkombination Alt + F11. Im VBA-Editor zeigen wir mit dem Menübefehl Extras|Verweise den Verweise-Dialog an. Hier selektieren Sie den Eintrag aus Bild 1 und fügen diese so hinzu.

Aktivieren des Verweises auf die Bibliothek Microsoft Office x.0 Object Library

Bild 1: Aktivieren des Verweises auf die Bibliothek Microsoft Office x.0 Object Library

Das Objektmodell zum Anpassen von Kontextmenüs

Zeigen wir nun mit F2 den Objektkatalog an, können wir dort die Bibliothek Office auswählen und finden dort beispielsweise die Auflistung CommandBars vor (siehe Bild 2). Diese bietet bereits einige interessante Elemente an. Unter anderem können wir damit die Anzahl aller aktuell verfügbaren CommandBar-Elemente ausgeben:

Die CommandBars-Auflistung im Objektkatalog

Bild 2: Die CommandBars-Auflistung im Objektkatalog

Debug.Print "Anzahl Commandbars: " _
     & Application.CommandBars.Count

Das liefert beispielsweise für Access die Anzahl von 247 CommandBar-Elemente, unter Excel immerhin noch 199 Einträge. Ob es sich dabei ausschließlich um Kontextmenüs handelt, finden wir gleich heraus. Unter Access können wir direkt auf die CommandBars-Auflistung zugreifen, unter Excel und Word müssen wir einen Verweis auf die Application-Klasse voranstellen. Bei dem Zugriff von COM-Add-Ins aus ist dies ohnehin obligatorisch, mehr dazu zeigen wir in einem Beispiel in einem weiteren Artikel namens Kontextmenü per COM-Add-In anpassen (www.vbentwickler.de/370).

CommandBar-Elemente durchlaufen

Mit den folgenden Zeilen aus der Prozedur CommandBarsDurchlaufen geben wir die Namen aller CommandBar-Elemente im Direktbereich des VBA-Editors aus:

Dim cbr As CommandBar
For Each cbr In Application.CommandBars
     Debug.Print cbr.Name
Next cbr

Das Gleiche gelingt auch per For…Next-Schleife über den 1-basierten Index:

Dim cbr As CommandBar
Dim i As Integer
For i = 1 To Application.CommandBars.Count
     Set cbr = Application.CommandBars.Item(i)
     Debug.Print cbr.Name
Next i

Die Ausgabe können wir noch verfeinern, indem wir zwei weitere Eigenschaften ausgeben lassen:

Debug.Print cbr.Name, cbr.Type, cbr.BuiltIn

Typ eines CommandBar-Elements ermitteln

Die erste hier verwendete Eigenschaft lautet Type. Type kann einen der folgenden drei Werte liefern:

  • 0 (msoBarTypeNormal): Das CommandBar-Element ist eine Symbolleiste.
  • 1 (msoBarTypeMenuBar): Das CommandBar-Element ist eine Menüleiste.
  • 2 (msoBarTypePopup): Das CommandBar-Element ist ein Kontextmenü.

Die ersten beiden Typen sind für unsere Zwecke nicht relevant. Bei diesen handelt es sich um die Typen der bis Office 2003 verwendeten Elemente, die dort angezeigt wurden, wo jetzt das Ribbon erscheint. Interessant wird es, wenn die Eigenschaft Type den Wert 2 liefert. Geben wie also nun alle Kontextmenüs aus und lassen uns, da wir deren Anzahl nicht über die Count-Eigenschaft bestimmen können, mit der Zählervariablen i den Index ausgeben:

Dim cbr As CommandBar
Dim i As Integer
For Each cbr In Application.CommandBars
     If cbr.Type = msoBarTypePopup Then
         i = i + 1
         Debug.Print i, cbr.Name, cbr.BuiltIn
     End If
Next cbr

Lassen wir die Prozedur unter Access laufen, erhalten wir 138 Kontextmenüs, unter Excel nur 67.

Eingebaute oder benutzerdefinierte Kontextmenüs

Mit der bereits verwendeten Eigenschaft BuiltIn können wir einen Boolean-Wert ausgeben, der angibt, ob es sich um ein eingebautes Kontextmenü handelt. Damit können wir die eingebauten Kontextmenüs von denen unterscheiden, die wir selbst per VBA hinzufügen.

Wozu die eingebauten Kontextmenüs nutzen?

Wozu sollten wir überhaupt wissen wollen, welche eingebauten Kontextmenü die jeweiligen Anwendungen anbieten? Weil es geschehen kann, dass wir nicht gleich ein vollständiges Kontextmenü mit neuen Funktionen hinzufügen wollen, sondern nur einzelne Funktionen, die in bestehenden Kontextmenüs angezeigt werden sollen.

Wenn wir beispielsweise unter Excel eine Funktion hinzufügen wollen, die nur im Zusammenhang mit einer Zelle angezeigt werden soll – also wenn der Benutzer mit der rechten Maustaste auf eine Zelle klickt – dann müssen wir den Namen dieses Kontextmenüs herausfinden und passen dann dieses Kontextmenü an.

Namen eines Kontextmenüs herausfinden

Den Namen eines Kontextmenüs kann man auf mehrere Arten ermitteln. Die erste ist die Ausgabe der Namen aller Kontextmenüs der jeweiligen Anwendung. Dazu führen wir die obige Prozedur zum Durchlaufen aller Kontextmenüs in der jeweiligen Anwendung aus. In vielen Fällen können wir schon am Namen des Kontextmenüs erkennen, wann dieses angezeigt wird.

Im Falle von Excel und einem Kontextmenü für eine Zelle werden wir schnell fündig – das Kontextmenü heißt Cell (siehe Bild 3).

Ausgabe der Kontextmenüs von Excel

Bild 3: Ausgabe der Kontextmenüs von Excel

Unter anderen Anwendungen wie Access ist es teilweise schwierig, das richtige Kontextmenü aufgrund der Benennung zu finden. In diesem Fall kommt eine zweite Technik zum Zuge.

Beispielkontextmenüs in den anderen Anwendungen

Unter Excel nutzen wir zu Beispielzwecken wie beschrieben die Kontextmenüs Cell oder Column. In der Beispieldatei für Word schauen wir uns in den Beispielen das Kontextmenü Text an, das beim Rechtsklick auf normalen Text im Dokument erscheint. In der Beispieldatei für Access verwenden wir das Kontextmenüs eines Elements des Navigationsbereichs namens Navigation Pane object Pop-up.

Name des Kontextmenüs in das Kontextmenü schreiben

Dabei greifen wir einer Technik vor, die wir weiter unten noch genauer erläutern. Wir fügen jedem Kontextmenü eine Schaltfläche hinzu, für deren Beschriftung wir den Namen des CommandBar-Elements festlegen. Dabei durchlaufen wir wieder alle Elemente der CommandBars-Auflistung und rufen jeweils für die Controls-Auflistung die Add-Methode auf. Dieser übergeben wir als ersten Parameter den Typ des zu erstellenden Steuerelements, in diesem Fall msoControlButton für eine Schaltfläche. Außerdem hinterlegen wir für den letzten Parameter Temporary den Wert True. Dies sorgt dafür, dass die angelegten Steuerelemente nur für die aktuelle Session der jeweiligen Anwendung angezeigt werden und bei einem weiteren Start nicht erneut erscheinen:

Public Sub NameInKontextmenuesSchreiben()
     Dim cbr As CommandBar
     Dim cbb As CommandBarButton
     Dim i As Integer
     For Each cbr In Application.CommandBars
         If cbr.Type = msoBarTypePopup Then
             Set cbb = cbr.Controls.Add( _
                 msoControlButton, , , , True)
             cbb.Caption = cbr.Name
         End If
     Next cbr
End Sub

Führen wir diese Prozedur aus und zeigen mit der rechten Maustaste eines der Kontextmenüs der Anwendung an, liefert dieses in einem neuen Eintrag den Namen des Kontextmenüs (siehe Bild 4).

Name eines CommandBar-Elements als Schaltflächenbeschriftung

Bild 4: Name eines CommandBar-Elements als Schaltflächenbeschriftung

Mit dem Namen eines Kontextmenüs können wir gezielt auf das jeweilige Kontextmenü zugreifen und dessen Elemente bearbeiten oder neue Elemente hinzufügen.

Elemente von Kontextmenüs ausgeben

Wir schauen uns dies zunächst beim Ausgeben der Steuerelemente eines Kontextmenüs an. Die folgende Prozedur referenziert das Kontextmenü Column von Excel (wenn Du den in einer anderen Anwendung ausprobieren möchtest, gib den Namen eines dort vorhandenen Steuerelements an). Dann durchläuft die Prozedur alle Elemente der Controls-Auflistung des CommandBar-Elements. Wichtig ist, dass wir die Laufvariable ctl mit dem Typ Object deklarieren. Der Hintergrund ist, dass die Controls-Auflistung verschiedene Steuerelementtypen enthalten kann. Deshalb geben wir im Folgenden direkt den Wert der Eigenschaft Type des jeweiligen Steuerelements aus. Noch eine bessere Methode, um den Typ zu ermitteln, ist die Ausgabe von TypeName(ctl):

Public Sub ElementeEinesKontextmenuesAusgeben()
     Dim cbr As CommandBar
     Dim ctl As Object
     Set cbr = Application.CommandBars("Column")
     For Each ctl In cbr.Controls
         Debug.Print ctl.Caption, ctl.Type, TypeName(ctl)
     Next ctl
End Sub

Die Ausgabe für das Column-Kontextmenü lautet:

Auss&chneiden           1            CommandBarButton
K&opieren               1            CommandBarButton
Einfü&gen               1            CommandBarButton
Inhalte einfü&gen...    1            CommandBarButton
Tabelle e&infügen       1            CommandBarButton
&Datentyp               10           CommandBarPopup
Zellen &einfügen        1            CommandBarButton
Zellen l&öschen         1            CommandBarButton
Inhal&te löschen        1            CommandBarButton
Zellen &formatieren...  1            CommandBarButton
Spalten&breite...       1            CommandBarButton
&Ausblenden             1            CommandBarButton
Einb&lenden             1            CommandBarButton
&Links entfernen        1            CommandBarButton
Änderun&gen anzeigen    1            CommandBarButton

Es gibt eine ganze Reihe von Steuerelementtypen, die Du im Objektkatalog unter der Auflistung msoControlType einsehen kannst. Wir können jedoch nur einige wenige nutzen. Unter den eingebauten Steuerelementen finden wir eine ganze Reihe verschiedener Typen, aber wir können nur drei davon mit der Add-Methode zur Controls-Auflistung hinzufügen:

  • 1 (msoControlButton): Schaltfläche
  • 4 (msoControlComboBox): Kombinationsfeld
  • 10 (msoControlPopup): Untermenü

Das erledigen wir beispielhaft mit der folgenden Prozedur. Hier fügen wir nicht nur die drei verschiedenen Typen hinzu, sondern zeigen gleich noch das angepasste Kontextmenü mit der Methode ShowPopup an:

Public Sub ElementeAnlegen()
     Dim cbr As CommandBar
     Dim ctl As Object
     Set cbr = Application.CommandBars("Column")
     Set ctl = cbr.Controls.Add(1, , , , True)
     ctl.Caption = "msoControlButton"
     Set ctl = cbr.Controls.Add(4, , , , True)
     ctl.Caption = "msoControlComboBox"
     Set ctl = cbr.Controls.Add(10, , , , True)
     ctl.Caption = "msoControlPopup"
     cbr.ShowPopup
End Sub

Möchten Sie weiterlesen? Dann lösen Sie Ihr Ticket!
Hier geht es zur Bestellung des Jahresabonnements des Magazins Visual Basic Entwickler:
Zur Bestellung ...
Danach greifen Sie sofort auf alle rund 200 Artikel unseres Angebots zu - auch auf diesen hier!
Oder haben Sie bereits Zugangsdaten? Dann loggen Sie sich gleich hier ein:

Schreibe einen Kommentar