TreeView mit Ribbon-Einträgen

Die Programmierung des TreeView-Steuerelements haben wir bereits in vielen Beiträgen dokumentiert. Dort haben wir auch gezeigt, wie Sie Befehle für spezielle Elementtypen im TreeView in Kontextmenüs unterbringen, die beim Rechtsklick auf die jeweiligen Elemente angezeigt werden. Es gibt noch eine andere Möglichkeit, solche Befehle abhängig vom Elementtyp abzubilden: als Ribbon-Einträge. Wie das gelingt, zeigt der vorliegende Beitrag.

Beispieldatenbank

Im Beitrag TreeView mit Kontextmenü (www.access-im-unternehmen.de/1243) haben wir bereits Vorarbeiten für diesen Beitrag geleistet und ein funktionsfähiges TreeView-Steuerelement mit den Daten aus den beiden Tabellen tblKunden und tblProjekte gefüllt.

Dort haben wir beschrieben, wie Sie die Daten im TreeView mit Kontextmenü-Einträgen anpassen können. Im vorliegenden Beitrag wollen wir nun zeigen, wie Sie die entsprechenden Befehle in einem Ribbon unterbringen, das nur dann angezeigt wird, wenn der Benutzer auf ein Element eines bestimmten Typs klickt – also beispielsweise auf ein Kunden-Element oder ein Projekt-Element.

Das Ribbon soll dann die gleichen Befehle anzeigen, die auch das Kontextmenü zu dem entsprechenden Eintrag anzeigt und die gleichen Funktionen auslösen (siehe Bild 1). Wir beginnen mit der Beispieldatenbank TreeViewMitRibbon.accdb.

Die Befehle dieses Kontextmenüs wollen wir im Ribbon anzeigen, wenn der Benutzer einen der Einträge im TreeView anklickt.

Bild 1: Die Befehle dieses Kontextmenüs wollen wir im Ribbon anzeigen, wenn der Benutzer einen der Einträge im TreeView anklickt.

Tabelle für die Ribbon-Definitionen anlegen

Wenn Sie Ribbons anzeigen möchten, benötigen Sie eine Tabelle namens USysRibbons, die nach einem bestimmten Schema aufgebaut ist und die Ribbon-Definitionen aufnimmt. Diese Tabelle enthält die folgenden drei Felder:

  • ID: Primärschlüsselfeld der Tabelle mit Autowert-Funktion
  • Ribbonname: Name des Ribbons
  • RibbonXML: XML-Definition des Ribbons

Die Tabelle mit dem Namen USysRibbons wird aufgrund des Präfixes USys… als Systemobjekt erkannt und wird nur angezeigt, wenn Sie in den Navigationsoptionen von Access die Option Systemobjekte anzeigen aktivieren.

Diese Tabelle füllen wir dann gleich mit den gewünschten Ribbon-Definitionen (siehe Bild 2). Mit der ersten möchten wir erreichen, dass beim Anklicken eines der Kunde-Elemente im TreeView-Steuerelement ein kontextabhängiges Ribbon-Tab zum Ribbon hinzugefügt wird.

Die Tabelle USysRibbons mit den Ribbon-Definitionen

Bild 2: Die Tabelle USysRibbons mit den Ribbon-Definitionen

Deshalb deklarieren wir dieses wie in Listing 1. Das Element customUI enthält zwei Callback-Attribute:

<xml version="1.0">
<customUI xmlns="http://schemas.microsoft.com/office/2009/07/customui" onLoad="OnLoad_RibbonKunde"
      loadImage="loadImage">
   <ribbon>
     <contextualTabs>
       <tabSet idMso="TabSetFormReportExtensibility">
         <tab id="tabKunde" label="Kunden">
           <group id="grpKunde" label="Kunde">
             <button image="user_delete_32" label="Kunde löschen" id="btnKundeLoeschen" onAction="onAction" 
                 size="large"/>
             <button image="folder2_plus_32" label="Neues Projekt" id="btnNeuesProjekt" onAction="onAction" 
                 size="large"/>
             <button onAction="onAction" size="large" image="edit_32" label="Umbenennen" id="btnKundeUmbenennen"/>
           </group>
           <group id="grpZwischenablage" label="Zwischenablage">
             <button id="btnAusschneiden" image="cut_32" label="Ausschneiden" onAction="onAction" size="large"/>
             <button id="btnKopieren" image="copy_32" label="Kopieren" onAction="onAction" size="large"/>
             <button image="clipboard_paste_32" label="Einfügen" id="btnEinfuegen" onAction="onAction" size="large"/>
           </group>
         </tab>
       </tabSet>
     </contextualTabs>
   </ribbon>
</customUI>

Listing 1: Definition des ersten Ribbons, das beim Anklicken eines Kunden angezeigt werden soll

  • onLoad: Dieses Callback wird einmalig beim Laden der Ribbon-Definition ausgeführt. Die Callback-Funktion dient meist dazu, eine Variable des Typs IRibbonUI mit einem Verweis auf die Ribbon-Definition zu füllen, was auch hier der Fall ist.
  • loadImage: Dieses Callback wird ausgelöst, wenn die Ribbon-Definition Elemente enthält, für die das Attribut image auf ein anzuzeigendes Bild eingestellt ist. Sie muss durch den Entwickler gefüllt werden, damit das Ribbon-Element das gewünschte Bild anzeigt.

Das ribbon-Element könnte man mit dem Attribut startFromScratch=”true” ausstatten, wenn man möchte, dass alle anderen und eingebauten Elemente des Ribbons beim Anzeigen ausgeblendet werden. Wir wollen dem Benutzer aber hier die Möglichkeit geben, dennoch die Befehle in den übrigen Ribbon-Tabs zu verwenden.

Um Ribbon-Tabs so anzuzeigen, dass sie nur im Kontext mit einem bestimmten Formular oder Element erscheinen, verwenden wir nicht die üblicherweise genutzte tabs-Auflistung, sondern das Element contextualTabs. Dieses geht meist einher mit dem untergeordneten Element tabSet, dem wir über das Attribut idMso mit dem Wert TabSetFormReportExtensibility die Information mitgeben, dass es gemeinsam mit Formularen oder Berichten angezeigt wird.

Danach folgt ein herkömmliches tab-Element mit der Beschriftung Kunden, darunter zwei group-Elemente. Das erste erhält die Beschriftung Kunde, das zweite die Beschriftung Zwischenablage. Die erste Gruppe enthält die drei Befehle Kunde löschen, Neues Projekt und Umbenennen. Für alle button-Elemente legen wir über das Attribut image den Namen des für diese Schaltfläche anzuzeigenden Bildes fest.

Außerdem stellen wir mit size=”large” ein, dass große Schaltflächen angezeigt werden sollen. Schließlich erhalten alle Schaltflächen das Attribut onAction mit dem Namen der Callback-Funktion, die beim Anklicken der Schaltfläche aufgerufen werden soll. Warum erhalten alle Schaltflächen den Aufruf der gleichen Callback-Funktion namens onAction Weil diese als Parameter den Namen des aufrufenden Elements erhält und wir in dieser Prozedur prüfen, von welchem Element der Aufruf kommt und die entsprechenden Befehle ausführen.

Dies soll ein Ribbon wie in Bild 3 ergeben. In den folgenden Abschnitten sehen wir uns an, wie wir das realisieren.

Das Ribbon zu den Kundeneinträgen im TreeView-Steuerelement

Bild 3: Das Ribbon zu den Kundeneinträgen im TreeView-Steuerelement

Ribbon-Verweis speichern

Wie oben erwähnt, soll beim Laden des Ribbons ein Verweis auf die Ribbon-Definition in einer Variablen gespeichert werden. Für diesen und anderen Ribbon-relevanten Code legen wir ein neues Modul namens mdlRibbons an. Diesem fügen wir als Erstes eine Variable für unser soeben definiertes Ribbon hinzu:

Public objRibbon_RibbonKunde As IRibbonUI

Dann können wir auch schon die Callback-Funktion implementieren, die wir für das Attribut onLoad des customUI-Elements der Ribbon-Definition angegeben haben. Diese sieht wie folgt aus:

Sub onLoad_RibbonKunde(ribbon As IRibbonUI)
     Set objRibbon_RibbonKunde = ribbon
End Sub

Callback zum Zuweisen von Bildern

Danach legen wir die Callback-Prozedur an, die wir für das Callback-Attribut loadImage hinterlegt haben. Diese finden Sie in Listing 2. Die Prozedur erhält den für das Attribut image des jeweiligen Steuerelements angegebenen Namen des Bildes.

Public Sub loadImage(control, ByRef image)
     Dim lngID As Long
     On Error Resume Next
     lngID = Nz(DLookup("ID", "MSysResources", "Name = '" & control & "'"), 0)
     If Err.Number = 3078 Then
         MsgBox "Die Tabelle 'MSysResources' mit den Images für die Anzeige im Ribbon fehlt." & vbCrLf _
             & "Fügen Sie die Images mit dem Ribbon-Admin hinzu", vbOKOnly + vbExclamation, _
                 "Tabelle MSysResources fehlt"
         Exit Sub
     End If
     On Error GoTo 0
     If lngID = 0 Then
         MsgBox "Das Image '" & control & "' ist nicht in der Tabelle MSysResources vorhanden. " & vbCrLf _
             & "Fügen Sie dieses über den Kontextmenüeintrag 'Benutzerdefiniertes Image hinzufügen' " & vbCrLf _
             & "des image-Attributs des entsprechenden Ribbon-Steuerelements hinzu."
     Else
         Set image = PicFromSharedResource_Ribbon(CStr(control))
     End If
End Sub

Listing 2: Callback-Prozedur zum Laden der Bilder in die Ribbon-Schaltflächen

Sie wird für jedes Steuer-element, das dieses Attribut enthält, einmal aufgerufen. Die Prozedur greift auf Bilddateien zu, die in der Tabelle MSysResources hinterlegt sein müssen. Wie Sie diese dort hinterlegen, haben wir bereits im Beitrag TreeView mit Kontextmenü (www.access-im-unternehmen.de/1243) kurz beschrieben – in diesem Fall verwenden wir allerdings Bilder im Format 32 x 32 statt 16 x 16.

Die Funktion prüft mit einem Aufruf der DLookup-Funktion, ob sich in der Tabelle MSysResources ein Datensatz befindet, dessen Feld Name den Namen des Bildes aufweist und schreibt den gegebenenfalls gefundenen Primärschlüsselwert in die Variable lngID. Die Datensätze in der Tabelle MSysResources sehen etwa wie in Bild 4 aus.

Die Tabelle MSysResources mit den Bildern für das Ribbon

Bild 4: Die Tabelle MSysResources mit den Bildern für das Ribbon

Hier kann es zu einem Fehler kommen, wenn die Tabelle MSysResources gar nicht vorhanden ist. Der Fehler hat die Nummer 3078. Tritt dieser Fehler auf, zeigt die Prozedur eine entsprechende Fehlermeldung an und die Prozedur wird beendet.

Anderenfalls prüft die Prozedur, ob lngID den Wert 0 hat. Das ist der Fall, falls die DLookup-Funktion keinen passenden Datensatz gefunden hat.

Auch in diesem Fall erscheint eine Meldung, die tunlichst während der Entwicklung der Anwendung auftreten sollte, damit der Entwickler die fehlenden Bilddateien zur Tabelle MSysResources hinzufügen kann.

Ist lngID jedoch nicht 0, dann wurde ein passender Datensatz gefunden. Dann übergeben wir den Namen des Steuerelements an die Funktion PicFromSharedResource_Ribbon, welche ein Objekt des Typs StdPicture zurückgibt. Dieses wird dann als Ergebnis der Callback-Funktion dem auslösenden Steuer-element zugewiesen.

Die Funktion PicFromSharedResource_Ribbon und einige andere nützliche Bildfunktionen finden Sie im Modul mdlRibbonImages.

Damit haben wir nun folgende Dinge erledigt:

  • Das Ribbon wird beim Aufruf über die Prozedur onLoad mit der Variablen objRibbon_RibbonKunde referenziert und
  • die Steuer-elemente werden durch die Funktion load-Image mit den zugeordneten Bildern gefüllt.

Ribbon anzeigen, wenn Kunde den Fokus im TreeView-Steuerelement erhält

Nun geht es weiter. Wir müssen dafür sorgen, dass dieses Ribbon angezeigt wird, sobald der Benutzer im TreeView-Steuerelement des Formulars frmKundenProjekte auf eines der Kunden-Elemente klickt.

Aber wie wollen wir das erledigen Immerhin gibt es nur die folgenden beiden Möglichkeiten, überhaupt für die Anzeige von Ribbons zu sorgen, deren Definitionen in der Tabelle USysRibbons gespeichert sind:

  • Durch Zuweisen des Namens des Ribbons an die Option Name des Menü-bands im Dialog Access-Optionen (siehe Bild 5) – dies stellt das Ribbon ein, das direkt nach dem Start von Access angezeigt werden soll -, oder
  • Einstellen des Anwendungsribbons

    Bild 5: Einstellen des Anwendungsribbons

  • durch Zuweisen des Namens des Ribbons an die Eigenschaft Name des Menübands eines Formulars oder Berichts. Dies stellt ein, welches Ribbon angezeigt werden soll, wenn das Formular geöffnet wird.

Die erste Option fällt flach, weil man diese zwar zur Laufzeit neu einstellen kann, die Änderung aber erst nach einem Neustart der Access-Anwendung wirksam wird.

Bleibt die zweite Option – können wir damit mehr anfangen Ja, denn das Ribbon eines Formulars oder Berichts kann man auch zur Laufzeit ändern. Stellt man per VBA die Eigenschaft RibbonName eines Formulars oder Berichts auf einen neuen Wert ein, dann wird die angegebene Ribbon-Definition auch direkt angewendet.

Nun zählen wir eins und eins zusammen und probieren es so, dass wir das Ereignis abfangen, das beim Anklicken eines TreeView-Elements ausgelöst wird, dort prüfen, welchen Elementtyp der Benutzer gerade angeklickt hat und in Abhängigkeit davon das entsprechende Ribbon anzeigen – indem wir die Eigenschaft RibbonName anpassen.

Zweites Ribbon hinzufügen

Bevor wir das erledigen, fügen wir noch das zweite Ribbon hinzu, das beim Anklicken eines Projekts angezeigt werden soll. Wenn wir nur einen Elementtyp im TreeView-Steuerelement haben, brauchen wir den ganzen Aufwand gar nicht in dieser Form zu betreiben.

Die Definition des zweiten Ribbons für die Projekte finden Sie in Listing 3.

<xml version="1.0">
<customUI xmlns="http://schemas.microsoft.com/office/2009/07/customui" onLoad="OnLoad_RibbonProjekt" 
     loadImage="loadImage">
   <ribbon>
     <contextualTabs>
       <tabSet idMso="TabSetFormReportExtensibility">
         <tab id="tabProjekte" label="Projekte">
           <group id="grpProjekt" label="Projekt">
             <button id="btnProjektLoeschen" image="folder2_delete_32" getEnabled="getEnabled" 
                 label="Projekt löschen" onAction="onAction" size="large"/>
             <button id="btnProjektUmbenennen" image="edit_32" label="Projekt umbenennen" onAction="onAction" 
                 size="large"/>
           </group>
           <group id="grpZwischenablage" label="Zwischenablage">
             <button id="btnAusschneiden" image="cut_32" label="Ausschneiden" onAction="onAction" size="large"/>
             <button id="btnKopieren" image="copy_32" label="Kopieren" onAction="onAction" size="large"/>
             <button id="btnEinfuegen" image="clipboard_paste_32" label="Einfügen" onAction="onAction" size="large"/>
           </group>
         </tab>
       </tabSet>
     </contextualTabs>
   </ribbon>
</customUI>

Listing 3: Dieses Ribbon soll angezeigt werden, wenn der Benutzer ein Element des Typs Projekt anklickt.

Ein wichtiger Unterschied zwischen den beiden Ribbon-Definitionen ist, dass die zweite eine andere Callback-Methode für das Callback-Attribut onLoad festlegt, nämlich in diesem Fall OnLoad_RibbonProjekt.

Für die zweite Ribbon-Definition müssen wir nämlich eine zweite Variable mit einem Verweis füllen, damit wir unabhängig auf die beiden Ribbons zugreifen können. Die Variable deklarieren wir wie folgt:

Ende des frei verfügbaren Teil. Wenn Du mehr lesen möchtest, hole Dir ...

den kompletten Artikel im PDF-Format mit Beispieldatenbank

diesen und alle anderen Artikel mit dem Jahresabo

Schreibe einen Kommentar