Es gibt einige Access-Optionen, die man immer wieder nutzt. In meinem Fall ist es zum Beispiel die Einstellung, ob Formulare nun als überlappende Fenster oder als Dokumente im Registerkartenformat angezeigt werden sollen. Sicher haben Sie ähnliche Einstellungen, die Sie oft ändern oder die Sie vielleicht einfach nur schnell einsehen möchten – was bei dem mittlerweile recht umfangreich gewordenen Optionen-Dialog schon einige Sekunden kosten kann. Warum also nicht ein COM-Add-In bauen, das die Informationen der wichtigsten Access-Einstellungen immer direkt im Ribbon anzeigt – anstatt irgendwo versteckt im Optionen-Dialog Und da wir mit twinBASIC auch noch ein praktisches Tool zum Erstellen von COM-Add-Ins zur Hand haben, können wir direkt loslegen!
Voraussetzung: Visual Studio Code und twinBASIC
Wenn Sie dauerhafte Ergänzungen oder Änderungen am Ribbon vornehmen wollen, benötigen Sie ein COM-Add-In. Eine andere Möglichkeit gibt es nur, wenn Sie mit den eingebauten Funktionen zum Anpassen der Benutzeroberfläche arbeiten wollen – und die sind bei Weitem nicht ausreichend.
Ein COM-Add-In konnten Sie früher mit Visual Studio 6 bauen, heutzutage mit Visual Studio .NET. Das ist allerdings nicht besonders komfortabel und erfordert umfangreichere Softwarevoraussetzungen als Visual Studio 6 gebaute COM-Add-Ins. Seit kurzem gibt es allerdings eine Erweiterung namens twinBASIC für Visual Studio Code, mit der Sie zum Beispiel COM-Add-Ins für Access und den VBA-Editor programmieren können. Wie das geht, haben wir bereits in den Beiträgen twinBASIC – VB/VBA mit moderner Umgebung (www.access-im-unternehmen.de/1303), twinBASIC – COM-Add-Ins für Access (www.access-im-unternehmen.de/1306) und anderen erläutert.
Im erstgenannten Beitrag erfahren Sie alles über die Installation, in letzterem die Grundlagen für das Erstellen von COM-Add-Ins. Details zu diesen Themen finden Sie in den genannten Beiträgen.
Neues COM-Add-In anlegen
Um ein neues COM-Add-In anzulegen, klicken Sie in Visual Studio Code links auf das twinBASIC-Symbol. Es erscheint eine Liste mit Projektvorlagen, wo Sie die Vorlage Sample 5 MyCOMAddin auswählen (siehe Bild 1).
Bild 1: Erstellen eines neuen COM-Add-Ins
Anschließend erscheint ein Dialog, in dem Sie die anzulegende Datei samt Verzeichnis auswählen. Hier geben wir amvAccessOptionsGoRibbon.twinproj an.
Dies fügt einige Dateien zum gewählten Verzeichnis hinzu, von denen die folgenden für uns interessant sind:
- amvAccessOptionsGoRibbon_ACCESS_RegisterAddin32.reg: Datei zum Hinzufügen der Registry-Einträge für das COM-Add-In
- amvAccessOptionsGoRibbon_ACCESS_UnregisterAddin32.reg: Datei zum Entfernen der Registry-Einträge für das COM-Add-In
- amvAccessOptionsGoRibbon_myCOMAddin.code-workspace: Arbeitsumgebung
- amvAccessOptionsGoRibbon_myCOMAddin.twinproj: Projektdatei
Das Projekt wird allerdings auch direkt in Visual Studio Code angezeigt.
Was bietet die Vorlage
Mit der Vorlage erhalten Sie bereits fast alles, was Sie benötigen:
- Die Implementierung der Schnittstelle IDTExtensibility2, die einige Ereignisprozeduren bereitstellt, die zu verschiedenen Zeitpunkten beim Verwenden des COM-Add-Ins ausgelöst werden – zum Beispiel beim Start (OnConnection)
- Die Implementierung der Schnittstelle IRibbonExtensibility in Form der Ereignisprozedur GetCustomUI. Diese wird beim Start des COM-Add-Ins ausgelöst und stellt das Ribbon zusammen, über das die Benutzeroberfläche beziehungsweise die Funktionen des COM-Add-Ins bereitgestellt werden sollen.
- Eine von dieser Ereignisprozedur aufgerufene Callback-Funktion, die zeigt, wie Sie Funktionen über das Ribbon aufrufen können.
COM-Add-In zum Laufen bringen
Dementsprechend brauchen Sie nur zwei Schritte zu erledigen, damit das COM-Add-In läuft:
- Das COM-Add-In kompilieren, indem Sie auf die Schaltfläche Build klicken (siehe Bild 2).
- Die Registrierungsdatei amvAccessOptionsGoRibbon_ACCESS_RegisterAddin32.reg starten, indem Sie diese doppelt anklicken und die folgenden Meldungen bestätigen.
Bild 2: COM-Add-In kompilieren
Wenn Sie nun eine Access-Datenbank öffnen, erscheint ein neuer Eintrag namens twinBASIC Test im Ribbon mit einer eigenen Schaltfläche (siehe Bild 3).
Bild 3: Das COM-Add-In ist nach wenigen Mausklicks einsatzbereit
Im Gegensatz zu dem COM-Add-In, das wir wie im Beitrag twinBASIC – COM-Add-Ins für Access erstellt haben, kann twinBASIC nun auch benutzerdefinierte Icons anzeigen. Wie Sie diese hinzufügen und über entsprechende Callback-Funktionen aufrufen, zeigen wir im Beitrag Benutzerdefinierte Bilder in twinBASIC (www.access-im-unternehmen.de/1325).
COM-Add-In vorbereiten
Da wir wissen, dass wir das COM-Add-In mit Access einsetzen wollen, können wir eine Objektvariable speziell zum Aufnehmen der aktuellen Access-Instanz deklarieren:
Private objAccess As Access.Application
Außerdem weisen wir diese in der Prozedur OnConnection wie folgt gezielt zu:
Sub OnConnection(ByVal Application As Object, _ ByVal ConnectMode As ext_ConnectMode, _ ByVal AddInInst As Object, _ ByRef custom As Variant()) _ Implements IDTExtensibility2.OnConnection Set objAccess = Application End Sub
Hier tragen wir den mit dem Parameter Application übergebenen Verweis auf die aktuelle Access-Instanz in die Variable objAccess ein.
Optionen mit dem Ribbon einstellen
Um Optionen mit dem Ribbon einzustellen, benötigen wir mehr als nur ein paar Schaltflächen. Immerhin wollen wir ja vor dem Ändern einer Option auch wissen, wie ihr aktueller Wert lautet! Also benötigen wir Steuerelemente wie Kontrollkästchen, Textfelder et cetera.
Da wir diese dynamisch einlesen und auch anpassen wollen, stellen wir ihre Werte zu Beginn mit entsprechenden Callback-Funktionen ein. Später ändern wir diese dann über das Ribbon und sorgen dafür, dass die Änderungen sich auch in den entsprechenden Access-Optionen niederschlagen.
Wir beginnen mit einer ersten Option, um uns den Ablauf anzusehen. Dies soll der Titel der Access-Anwendung sein. Der Vorteil gegenüber einigen anderen Optionen ist, dass wir Änderungen direkt in der Titelleiste angezeigt bekommen – im Gegensatz zu vielen anderen Optionen, die sich erst beim erneuten Öffnen der Datenbankanwendung zeigen.
Also fügen wir der Ribbon-Definition ein Textfeld hinzu. Danach sieht Prozedur GetCustomUI zur Definition des Ribbons wie in Listing 1 aus. Hier finden wir statt der bisher vorhandenen Schaltfläche ein editBox-Element. Für dieses haben wir die Eigenschaft label auf Datenbanktitel und maxLength auf 255 eingestellt. Letztere sorgt dafür, dass der Titel die maximale Zeichenzahl von 255 nicht überschreitet. Damit die editBox-Steuerelemente breit genug dargestellt werden, setzen wir außerdem das Attribut sizeString auf den Wert xxxxxxxxxxxxxxxxxxxxxxxxx. Außerdem haben wir gleich zwei Callback-Attribute definiert:
Private Function GetCustomUI(ByVal RibbonID As String) As String _ Implements IRibbonExtensibility.GetCustomUI Dim strXML As String strXML &= "<xml version="1.0">" & vbCrLf strXML &= "<customUI xmlns="http://schemas.microsoft.com/office/2009/07/customui">" & vbCrLf strXML &= " <ribbon>" & vbCrLf strXML &= " <tabs>" & vbCrLf strXML &= " <tab id="tabOptions" label="Optionen">" & vbCrLf strXML &= " <group id="grpThisDatabase" label="<Aktuelle Datenbank>">" & vbCrLf strXML &= " <editBox label="Datenbanktitel:"id="txtTitle" maxLength="255" " _ & " sizeString="xxxxxxxxxxxxxxxxxxxxxxxxx" getText="getText" onChange="onChange"/>" & vbCrLf strXML &= " </group>" & vbCrLf strXML &= " </tab>" & vbCrLf strXML &= " </tabs>" & vbCrLf strXML &= " </ribbon>" & vbCrLf strXML &= "</customUI>" & vbCrLf Return strXML End Function
Listing 1: Einlesen des Ribbons mit dem Textfeld zum Festlegen des Datenbanktitels
- getText: Gibt eine Callback-Funktion an, die beim erstmaligen Anzeigen oder der Anforderung der Aktualisierung der Anzeige ausgelöst werden soll. Hier wollen wir den aktuellen Titel aus den Access-Optionen einlesen und anschließend im editBox-Steuerelement anzeigen.
- onChange: Gibt eine Callback-Funktion an, die beim Ändern des Wertes des editBox-Steuerelements ausgelöst wird. Hiermit wollen wir nach Änderungen durch den Benutzer den neuen Wert in die Access-Optionen übertragen.
Einlesen des aktuellen Datenbanktitels
Die Callback-Funktion getText wird ausgelöst, wenn das Ribbon geladen oder wenn per Code eine der Methoden Invalidate oder InvalidateControl der in einer Variablen gespeicherten Ribbon-Instanz ausgelöst wird und das Steuerelement danach erstmals sichtbar wird.
Sie erhält als ersten Parameter einen Verweis auf das aufrufende Steuerelement. Der zweite Parameter erwartet die im editBox-Steuerelement anzuzeigende Zeichenkette.
Wenn Sie die Prozedur wie nachfolgend in das twinBASIC-Projekt einfügen, werden einige Elemente rot unterstrichen. Das liegt daran, dass wir noch keinen Verweis auf die DAO-Bibliothek hinzugefügt haben:
Function GetText(control As IRibbonControl) As String Dim db As DAO.Database Dim prp As DAO.Property Dim strText As String On Error Resume Next Set db = objAccess.CurrentDb Set prp = db.Properties("AppTitle") On Error GoTo 0 If prp Is Nothing Then strText = "<Kein Titel>" Else strText = prp.Value End If On Error GoTo 0 GetText = strText End Function
Das holen wir nach, indem wir in twinBASIC zum Bereich Settings wechseln und dort unter COM Type Library / Active X References einen Verweis auf die Bibliothek Microsoft Office 16.0 Access Database Engine Object Library [v12.0] hinzufügen (siehe Bild 4). Danach unbedingt mit Strg + S speichern, damit die Änderungen wirksam werden!
Bild 4: Hinzufügen eines Verweises auf die DAO-Bibliothek
Danach sind fast alle roten Unterstreichungen verschwunden, nur eine nicht – die unter CurrentDb. CurrentDb ist auch keine Eigenschaft der DAO-Bibliothek, sondern der Access-Bibliothek.
Also fügen wir auch diese noch mit dem Eintrag Microsoft Access 16.0 Object Library [v9.0] hinzu. Nach dem erneuten Speichern können wir uns nun den Code der Prozedur getText ohne rote Unterstreichungen ansehen.
Die Prozedur deaktiviert zunächst die eingebaute Fehlerbehandlung und ruft den Wert der Eigenschaft AppTitle des Database-Objekts der aktuellen Datenbank ab. Die Fehlerbehandlung deaktivieren wir dabei, weil ein Fehler ausgelöst wird, wenn diese Eigenschaft noch nicht oder nicht mehr vorhanden ist. Sie ist nur vorhanden, wenn diese bereits durch den Benutzer über den Optionen-Dialog von Access gesetzt wurde (oder per Code, wie wir gleich demonstrieren).
Danach aktivieren wir die Fehlerbehandlung wieder und prüfen per If…Then-Bedingung, ob prp eine Eigenschaft zugewiesen wurde.
Das ist nur der Fall, wenn die Eigenschaft aktuell vorhanden ist. Ist prp leer, übergeben wir die Zeichenkette
Andere Callback-Signatur in twinBASIC-Ribbons
Wie schon im Beitrag twinBASIC – COM-Add-Ins für Access festgestellt, sehen wir auch hier wieder eine andere Signatur für die Callback-Funktion. Sie lautet hier:
Function GetText(control As IRibbonControl) As String
Unter VBA würde diese lauten:
Sub getText(control As IRibbonControl, ByRef text)
Die hier verwendete Signatur ist die gleiche, die wir auch in einem VB6-COM-Add-In nutzen würden. Da twinBASIC zum Nachfolger von VB6 avanciert und wir noch weitere Tools damit entwickeln werden, stellen wir in einem weiteren Beitrag namens Ribbon: Callback-Signaturen für VBA und VB6 (www.access-im-unternehmen.de/1324) die Unterschiede vor.
Speichern des geänderten Datenbanktitels
Mit der gleichen Eigenschaft beschäftigt sich die Callback-Funktion onChange (siehe Listing 2). Diese hat die gleichen Parameter. Allerdings wird sie ausgelöst, wenn der Benutzer den im editBox-Steuerelement enthaltenen Text ändert und die Änderung beispielsweise durch Verlassen des Textfeldes abschließt. Dementsprechend ist der zweite Parameter text diesmal auch kein Rückgabeparameter, sondern er liefert den neu vom Benutzer eingegebenen Text.
Sub OnChange(control As IRibbonControl, text As String) Dim db As DAO.Database Dim prp As DAO.Property Set db = objAccess.CurrentDb If Len(text) = 0 Then db.Properties.Delete "AppTitle" Else On Error Resume Next Set prp = db.Properties("AppTitle") If Not Err.Number = 0 Then Set prp = db.CreateProperty("AppTitle", dbText, text) db.Properties.Append prp Else prp.Value = text End If End If objAccess.RefreshTitleBar End Sub
Listing 2: Ändern einer Option nach Änderung im Ribbon
Den Inhalt von text prüft die Prozedur zunächst in einer If…Then-Bedingung. Es kann sein, dass der Benutzer das editBox-Steuerelement komplett geleert hat, dann soll auch der Titel geleert werden. Das funktioniert allerdings nur in der gewünschten Form, indem wir die Eigenschaft AppTitle wieder löschen. Das erledigt die Prozedur im If-Teil der Bedingung mit der Delete-Methode der Properties-Auflistung.
Hat der Benutzer jedoch einen Titel mit mindestens einem Zeichen eingegeben, dann wollen wir die Eigenschaft AppTitle auf diesen Wert einstellen. Dazu versucht die Prozedur, nach vorheriger Deaktivierung der Fehlerbehandlung, die Eigenschaft mit der Variablen prp zu referenzieren. Ist dabei ein Fehler aufgetreten, erstellt die Prozedur die Eigenschaft neu und hängt diese an die Auflistung Properties des Database-Objekts der aktuellen Datenbank an.
Ist die Eigenschaft bereits vorhanden, stellt die Prozedur diese lediglich auf den Wert aus dem Parameter text ein.
In jedem Fall soll die Anzeige der Titelleiste anschließend aktualisiert werden, was die Methode RefreshTitleBar des Application-Objekts der aktuellen Access-Instanz erledigt. Diese haben wir ja zuvor in die Variable objAccess eingelesen.
Nachdem Sie die Ribbon-Definition in der Prozedur GetCustomUI angepasst und die beiden Callback-Funktionen hinzugefügt haben, können Sie die Änderungen speichern und das COM-Add-In neu kompilieren. Das Ergebnis der Kompilierung finden Sie übrigens unten in Visual Studio Code in der Debugging-Console.
Wenn Sie danach eine Access-Datenbank öffnen, finden Sie ein neues Tab namens Optionen im Ribbon. Klicken Sie es an, erscheint die von uns hinzugefügte Option zum Einstellen des Datenbanktitels (siehe Bild 5). Dieses zeigt direkt beim Öffnen den aktuellen Wert an – bei einer Datenbank, für die Sie noch keinen Anwendungstitel eingestellt haben, beispielsweise
Bild 5: Die erste Access-Option im Access-Ribbon
Option zum Ändern des Anwendungssymbols
Wir wollen gleich die nächste Option aus dem Optionen-Dialog ermitteln und ausprobieren, nämlich das Definieren eines Anwendungssymbosl. Hier haben wir die zusätzliche Herausforderung, dass wir einen Datei auswählen-Dialog hinzufügen wollen. Also benötigen wir nicht nur ein editBox-Steuerelement, sondern daneben auch noch ein button-Element. Damit diese nebeneinander erscheinen, fassen wir die beiden Elemente in einem box-Element zusammen. Die notwendige Erweiterung der Prozedur GetCustomUI sehen Sie in Listing 3.
Private Function GetCustomUI(ByVal RibbonID As String) As String _ Implements IRibbonExtensibility.GetCustomUI ... strXML &= " <editBox label="Anwendungstitel:" id="txtTitle" maxLength="255" getText="getText"" _ & " onChange="onChange"/>" & vbCrLf strXML &= " <box id="box1">" & vbCrLf strXML &= " <editBox label="Anwendungssymbol:" id="txtIcon" maxLength="255"" _ & " getText="getText" onChange="onChange"/>" & vbCrLf strXML &= " <button screentip="Symbol auswählen ..." label="..." id="btnChooseSymbol"" _ & " onAction="onAction"/>" & vbCrLf strXML &= " </box>" & vbCrLf ... End Function
Listing 3: Erweiterung der Ribbon-Definition für das Anpassen des Anwendungssymbols
Eigene Callback-Prozedur für gleiche Attribute für jedes Steuerelement
Bei Ereignisprozeduren von Formularen, Berichten oder Steuerelementen wird für jedes Ereignis eines jeden Elements eine neue Prozedur erstellt, die den Namen des Elements, einen Unterstrich und die Bezeichnung des Ereignisses als Bezeichnung trägt. Bei Callback-Funktionen des Ribbons hat es sich eingebürgert, dass man zum Beispiel für das Ereignis onAction nur eine Callback-Funktion namens onAction definiert. Diese ermittelt dann über den Parameter control und dessen Eigenschaft id den Namen des aufrufenden Steuerelements. In einer Select Case-Bedingung wird dann der Name ausgewertet und in den Case-Zweigen finden sich dann die Anweisungen, die für das jeweilige Steuerelement ausgeführt werden sollen.
Sie können natürlich auch beispielsweise für das onAction-Attribut eines Elements namens btnBeispiel einen Wert wie btnBeispiel_OnAction anlegen und eine entsprechende Callback-Funktion hinterlegen. Je nachdem, wie umfangreich das Ribbon ist und wie aufwendig der Code, kann dies die bessere Variante sein. Wir haben für die Lösung dieses Beitrags entschieden, die letztere Variante mit individuellen Callback-Funktionen je Steuerelement zu nutzen.
Das heißt zunächst, dass wir die bereits erstellten Callback-Funktion umbenennen. Aus der GetText-Funktion für das Textfeld txtTitle wird nun:
Function txtTitle_GetText(control As IRibbonControl) As String ... End Function
Die gleiche Änderung nehmen wir für die Callback-Funktion OnChange für das Textfeld txtTitle vor:
Sub txtTitle_OnChange(control As IRibbonControl, text As String) ... End Sub
Dementsprechend passen wir auch noch den Aufruf der Callback-Funktionen des editBox-Steuerelements txtTitle in den entsprechenden Attributen an:
<editBox label="Anwendungstitel:" id="txtTitle" maxLength="255" getText="txtTitle_getText" onChange="txtTitle_onChange"/>
Ribbon-Steuerelemente für das Anwendungssymbol
In den XML-Definitionen für die Steuerelemente im Ribbon verwenden wir direkt die entsprechenden neuen Bezeichnungen:
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