Ribbon für das Ticketsystem

Wir haben in Access im Unternehmen bereits einige Techniken rund um das Ribbon vorgestellt, aber noch sehr wenige unserer Lösungen tatsächlich mit der Ribbon-Technologie ausgestattet. Das wollen wir am Beispiel des Ticketsystems, das wir in einer eigenen Beitragsreihe behandeln, nachholen. Dort fügen wir nicht nur einige Ribbon-Schaltflächen zur Steuerung der Anwendung ein, sondern legen auch einen kleinen Backstage-Bereich zur Einstellung von Anwendungsoptionen an.

Neben den üblichen Schaltflächen, mit denen wir die Formulare und Funktionen der Anwendung aufrufen wollen, soll das Ticketsystem auch einen Backstagebereich erhalten, über den Sie Anwendungseinstellungen einsehen und ändern können. In diesem Fall ist in der Anwendung das Verzeichnis in Outlook festzulegen, in das der Benutzer die E-Mails ziehen soll, die vom Ticketsystem berücksichtigt werden sollen. Diesen Pfad speichern wir in der Datenbank in der Tabelle tblOptionen, die dafür das Feld Verzeichnis vorhält.

Der Backstagebereich soll wie in Bild 1 aussehen. Im Gegensatz zur Ribbonleiste selbst ist der Backstagebereich ein wenig komplizierter aufgebaut, aber das soll uns nicht aufhalten. Also schauen wir uns den Code an, der zur Definition unserer Optionen im Backstagebereich notwendig ist.

Benutzerdefinierter Backstage-Bereich

Bild 1: Benutzerdefinierter Backstage-Bereich

Der erste Abschnitt der XML-Definition enthält das Element customUI, in welchem wir die Callback-Funktionen für das Laden des Ribbons (onLoad) und für das Einlesen von Bilddateien (loadImage) festgelegt haben (s. Listing 1). Danach folgt die Definition der Ribbon-Leiste (ribbon), die wir uns weiter unten genauer ansehen. Schließlich legen wir das backstage-Element an, welches die Definition des Backstage-Bereichs enthält – oder in unserem Fall die Erweiterung des BackstageBereichs. Wie Sie der Abbildung entnehmen können, sind unter der aktuellen Definition noch alle eingebauten Elemente vorhanden, was zur Entwicklungszeit durchaus noch sinnvoll sein kann. Später werden wir diese Elemente weitgehend ausblenden.

<xml version="1.0">
<customUI xmlns="http://schemas.microsoft.com/office/2009/07/customui" onLoad="OnLoad_Main" loadImage="loadImage">
   <ribbon>
...
   </ribbon>
   <backstage>
     <tab id="tabEinstellungenBackstage" label="Einstellungen" title="Ticketsystem" firstColumnMaxWidth="600">
       <firstColumn>
         <group id="grpOutlook" label="Outlook-Einstellungen" style="normal" helperText="Enthält Einstellungen 
               zur Interaktion mit Microsoft Outlook">
           <primaryItem/>
           <topItems>
             <labelControl id="lblVerzeichnisFuerTickets" label="Verzeichnis für Tickets:"/>
             <layoutContainer id="xxx33091" align="left">
               <hyperlink id="hypVerzeichnisFuerTickets" getLabel="getLabel" onAction="onAction"/>
               <button id="btnOrdnerAendern" onAction="onAction" label="Ordner ändern"/>
             </layoutContainer>
           </topItems>
           <bottomItems/>
         </group>
       </firstColumn>
     </tab>
   </backstage>
</customUI>

Listing 1: Definition des Backstage-Bereichs

Vorab noch kurz zu den beiden durch die Callbacks onLoad und loadImage ausgelösten Prozeduren. onLoad löst die folgende Prozedur aus, die wir, wie die meisten anderen mit dem Ribbon in Zusammenhang stehenden Prozeduren, im Modul mdlRibbon untergebracht haben:

Sub onLoad_Main(ribbon As IRibbonUI)
     Set objRibbon_Main = ribbon
End Sub

Die hier verwendete Variable deklarieren wir wie folgt im gleichen Modul:

Public objRibbon_Main As IRibbonUI

Diese Variable müssen wir mit einem Verweis auf die geladene Ribbon-Definition füllen, damit wir ihre Methoden Invalidate und InvalidateControl auslösen können. Diese sorgen dafür, dass die Inhalte, Bilder und weiteren Eigenschaften neu geladen werden, sollten sich die Anforderungen geändert haben. Die Callback-Eigenschaft loadImage ruft die Prozedur aus Listing 2 auf. Diese soll zunächst prüfen, ob die Tabelle MSysResources, welche die Bilder enthält, die im Ribbon angezeigt werden sollen, in der Datenbank vorhanden ist.

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: Prozedur zum Laden der Ribbon-Bilder

Die Prozedur loadImage wird für jedes Bild, das in ein Steuerelement des Ribbons geladen werden soll, je einmal aufgerufen. Dabei wird mit dem Parameter image jeweils der Name des zu verwendenden Bildes übergeben. Dieser ist immer in der Definition des jeweiligen Objekts für das Attribut image enthalten, also beispielsweise:

<button id="btnOffeneMails" image="mail" label="Offene Mails" onAction="onAction" size="large"/>

Damit wird dann die Funktion PicFromSharedResource_Ribbon aufgerufen, die sich, wie einige andere für die Ermittlung von Bildern aus der Tabelle MSysResources, im Modul mdlRibbonImages befindet (siehe Beispieldatenbank). Doch zurück zur Backstage-Definition. Diese wird durch je ein öffnendes und schließendes backstage-Element eingeschlossen. Damit unser Eintrag unten unter den übrigen eingebauten Elementen angezeigt wird, fügen wir unterhalb des backstage-Elements ein tab-Element hinzu. Diesem geben wir eine Beschriftung, einen Titel und eine Breite mit. Der Titel ist groß und breit im Bereich rechts neben der vertikalen Tableiste zu erkennen:

<tab id="tabEinstellungenBackstage" label="Einstellungen" title="Ticketsystem" firstColumnMaxWidth="600">

Wir benötigen nur eine der zwei möglichen Spalten, also legen wir unter dem tab-Element nur ein firstColumn-Element an, das die übrigen Elemente enthält. Zum Beispiel das group-Element, dem wir ein leeres primaryItem-Element, ein mit einigen Elementen gefülltes topItems-Element und ein wiederum leeres bottomItems-Element hinzufügen. Das group-Element enthält auch einige Attribute zum Beispiel eine Beschriftung (Outlook-Einstellungen) und einen helperText, der unterhalb der Beschriftung erscheint:

<group id="grpOutlook" label="Outlook-Einstellungen" style="normal" 
helperText="Enthält Einstellungen zur Interaktion mit Microsoft Outlook">

Unter topItems fügen wir einige Elemente hinzu – als Erstes ein labelControl, das eine Beschriftung enthält:

<labelControl id="lblVerzeichnisFuerTickets" label="Verzeichnis für Tickets:"/>

Darunter wollen wir dann zwei Elemente nebeneinander anordnen, weshalb wir einen layoutContainer mit linkszentrierter Ausrichtung nutzen:

<layoutContainer id="xxx33091" align="left">
     ...
</layoutContainer>

Das erste Element ist ein hyperlink-Element, das über die Callback-Funktion getLabel mit einer Beschriftung gefüllt wird und deren onAction-Callback die VBA-Prozedur onAction auslöst. Dieses Element ist logischerweise wie ein Hyperlink ausgezeichnet, also in blauer und unterstrichener Schrift:

<hyperlink id="hypVerzeichnisFuerTickets" getLabel="getLabel" onAction="onAction"/>

Rechts daneben landet ein Button mit der Beschriftung Ordner ändern.

Er ist wie folgt definiert und soll die Auswahl eines neuen Ordners ermöglichen:

<button id="btnOrdnerAendern" onAction="onAction" label="Ordner ändern"/>

Logik hinter dem Backstage-Bereich

Die Steuerelemente des Backstage-Bereichs enthalten ein paar Callback-Attribute, die wir im VBA-Modul mdlRibbons um entsprechende Prozeduren anreichern.

Die erste sorgt dafür, dass bei einem Klick auf die Schaltfläche Ordner ändern der Outlook-Dialog zum Auswählen eines der Outlook-Ordner angezeigt wird (s. Bild 2). Dies löst die Prozedur onAction aus und übergibt dieser per Parameter einen Verweis auf das auslösende Steuerelement. Dessen Name ermitteln wir mit der Eigenschaft ID des Parameters Control und führen nach Steuerelement einen der Zweige einer Select Case-Bedingung aus:

Aufruf des Ordner auswählen-Dialogs von Outlook

Bild 2: Aufruf des Ordner auswählen-Dialogs von Outlook

Sub onAction(Control As IRibbonControl)
     Dim objOutlook As Outlook.Application
     Dim objNamespace As Outlook.NameSpace
     Dim objFolder As Outlook.Folder
     Dim strOrdner As String
     Select Case Control.ID
         Case "btnOrdnerAendern"
             Call OutlookOrdnerAuswaehlen
         ...
     End Select
End Sub

In unserem Fall handelt es sich um den Zweig mit dem Wert btnOrdnerAendern, der lediglich den Aufruf einer weiteren Prozedur namens OutlookOrdnerAuswaehlen enthält.

Outlook-Ordner auswählen

Die Prozedur OutlookOrdnerAuswaehlen sieht wie in Listing 3 aus. Sie ermittelt zunächst den Namen des aktuell aktiven Fensters, und zwar mit einer Hilfsfunktion namens GetActiveWindowTitle.

Public Sub OutlookOrdnerAuswaehlen()
     Dim strOrdner As String
     Dim db As DAO.Database
     Dim lngCount As Long
     Dim strFenster As String
     strFenster = GetActiveWindowTitle
     strOrdner = GetFolderName
     Set db = CurrentDb
     db.Execute "UPDATE tblOptionen SET Verzeichnis = ''" & strOrdner & "''", dbFailOnError
     lngCount = db.RecordsAffected
     If lngCount = 0 Then
         db.Execute "INSERT INTO tblOptionen(Verzeichnis) VALUES(''" & strOrdner & "'')", dbFailOnError
     End If
     objRibbon_Main.InvalidateControl "hypVerzeichnisFuerTickets"
     AppActivate strFenster
End Sub

Listing 3: Die Prozedur zum Auswählen eines neuen Outlook-Ordners

Diese nutzt zwei API-Funktionen, nämlich GetForegroundWindow und GetWindowText, die im Kopf des Moduls mdlAPI deklariert werden (s. Listing 4). Die Funktion GetActiveWindowTitle ermittelt zunächst mit der Funktion GetForeGroundWindow ein Handle auf das aktive Fenster. Dann liest sie mit GetWindowText den Titel des Fensters ein und gibt diesen als Rückgabewert der Funktion zurück. Nachdem der Fenstertitel des aktiven Fensters so in der Variablen strFenster der Prozedur OutlookordnerAuswaehlen gelandet ist, ruft diese eine weitere Funktion namens GetFolderName auf. Diese ist scheinbar recht einfach gestrickt, denn sie ruft lediglich die Methode PickFolder eines Objekts namens GetMAPI auf:

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