Flexible Schnellsuche

Wer kennt das nicht als Entwickler: Man möchte mal eben schnell in einer Tabelle nach einem bestimmten Datensatz suchen. Und das auch noch wiederholt, sodass man immer noch den Filter entfernen und diesen neu setzen muss – wozu wir die eingebauten Filter-Elemente der Datenblattansicht nutzen. Viel schöner wäre es doch, wenn wir mal eben das Kriterium und weitere Einstellungen über das Ribbon steuern könnten – während wir die Daten beim Filtern betrachten. Genau dazu haben wir uns für den Eigenbedarf eine kleine Schnellsuche gebaut, die wir in diesem Beitrag vorstellen. Das Beste: Selbst wenn Sie gar nicht genau erfahren wollen, wie es funktioniert, finden Sie die Lösung für 32-Bit- und 64-Bit-Access im Download zu diesem Beitrag.

Das Tool soll gar keine aufwendigen Aufgaben erledigen: Wir wollen schlicht und einfach im Ribbon ein Feld haben, in das wir einen Vergleichswert eingeben können.

Die Suche wollen wir durch Betätigen der Eingabetaste oder einer Schaltfläche starten.

Zum einen möchten wir nur das aktuell markierte Feld oder alle Felder nach dem gesuchten Inhalt filtern und zum anderen möchten wir festlegen, ob der gesamte Feldinhalt mit dem Suchbegriff übereinstimmen muss oder ob der Suchbegriff nur im Feld enthalten sein soll. All dies sehen wir in Bild 1. Hier haben wir das Textfeld zur Eingabe des Filters, die beiden Schaltflächen zum Aktivieren und Deaktivieren des Filters sowie die beiden Optionen für das Durchsuchen des kompletten Feldinhalts und für das aktuelle Feld oder alle Felder.

Ribbon-Funktion zur Schnellsuche in Datenblättern und Formularen

Bild 1: Ribbon-Funktion zur Schnellsuche in Datenblättern und Formularen

Eine solche Erweiterung können wir einer einzelnen Access-Anwendung hinzufügen, indem wir die entsprechende Ribbondefinition anlegen und die dadurch aufgerufenen Funktionen hinzufügen.

COM-Add-In mit twinBASIC

Wir wollen diese Funktion allerdings in allen Access-Anwendungen nutzen, jedoch nicht die Funktion in alle Access-Anwendungen einbauen. Deshalb haben wir ein COM-Add-In auf Basis von twinBASIC programmiert. Wie das COM-Add-In funktioniert, zeigen wir in diesem Beitrag. Wenn Sie das COM-Add-In anpassen oder erweitern oder ein neues COM-Add-In auf Basis dieses Add-Ins erstellen wollen, sind Sie nach der Lektüre dieses Beitrags bestens gerüstet. Alles, was man braucht, ist die aktuelle Version der für 32-Bit-Anwendungen kostenlosen twinBASIC-Entwicklungsumgebung, zum Beispiel von hier:

https://github.com/twinbasic/twinbasic/releases

Dabei handelt es sich um eine .exe-Datei mit einigen weiteren Dateien, die Sie nur auf Ihre Festplatte extrahieren und starten müssen, zum Beispiel durch einen Doppelklick auf die Datei amvFastSearch.twinproj aus dem Download zu diesem Beitrag.

Code des COM-Add-Ins

Das Projekt enthält nur zwei Module. Das erste namens DllRegistration.twin enthält lediglich die beiden Funktionen, die beim Registrieren und beim Aufheben der Registrierung durchgeführt werden sollen. Diese werden sowohl ausgeführt, wenn wir in twinBASIC den Befehl File|Build aufrufen als auch dann, wenn wir die fertig erstellte .dll-Datei mit dem Befehl Regsvr32.exe registrieren. Diese enthalten die Informationen, die dann in die Registry geschrieben werden sollen und beim Start von Access ausgelesen werden. Weiter unten zeigen wir jedoch auch noch, wie die Registrierung über die Benutzeroberfläche funktioniert.

Beim Start des COM-Add-Ins

Ist das COM-Add-In einmal registriert, wird es beim Start von Access eingelesen und verschiedene Ereignisprozeduren der beiden Schnittstellen des COM-Add-Ins werden ausgelöst. Das COM-Add-In implementiert die beiden Schnittstellen IDTExtensibility2 und IRibbonExtensibility. Die erste sorgt dafür, dass das COM-Add-In beim Starten von Access ebenfalls gestartet wird und einen Verweis auf die Access-Instanz erhält. Die zweite enthält nur eine Funktion, mit der sich Access eine Ribbondefinition holen kann, die wir im COM-Add-In zusammenstellen.

Bevor wir uns die Prozeduren ansehen, die beim Start ausgelöst werden, werfen wir einen Blick auf einige Variablen, die wir im Kopf der Klasse amvFastSearch unterbringen:

Private objAccess As Access.Application
Private objRibbon As IRibbonUI
Private bolKompletterFeldinhalt As Boolean
Private bolNurAktuellesFeld As Boolean
Private strVergleichswert As String

Die erste nimmt einen Verweis auf die Access-Instanz auf, die das COM-Add-In verwendet. Die zweite erhält nach dem Erstellen des Ribbons einen Objektverweis auf die Definition, damit wir darüber auf bestimmte Ereignisse reagieren können.

Die übrigen Variablen sind bereits für das Speichern der Informationen vorgesehen, die wir über die Ribbon-Benutzerschnittstelle des Tools eingeben.

Beim Verbinden des COM-Add-Ins

Wenn Access gestartet wird und das COM-Add-In über die Registry als aktiv identifiziert, wird dieses aufgerufen und erhält über die Ereignisprozedur OnConnection mit dem Parameter Application einen Verweis auf die aufrufende Access-Instanz. Dieser wird direkt in der Variablen objAccess gespeichert:

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

Es gibt noch weitere Ereignisprozeduren für das COM-Add-In, aber die sind für uns nicht weiter interessant. Wichtig ist nur, dass sie überhaupt implementiert werden.

Ribbondefinition zusammenstellen

Die Funktion GetCustomUI stellt die Ribbondefinition zusammen und gibt diese an Access zurück, damit diese dort angewendet werden kann (siehe Listing 1). Das Ribbon besteht aus einem customUI-Element mit den Callback-Ereignissen loadImage und onLoad. Die für onLoad hinterlegte Prozedur wird einmalig beim Einlesen der Ribbondefinition ausgeführt.

Private Function GetCustomUI(ByVal RibbonID As String) As String Implements IRibbonExtensibility.GetCustomUI
     Dim strXML As String
     strXML &= "<customUI xmlns=""http://schemas.microsoft.com/office/2009/07/customui"" loadImage=""LoadImage"" " _
         & "onLoad=""onLoad"">" & vbCrLf
     strXML &= "  <ribbon startFromScratch=""false"">" & vbCrLf
     strXML &= "    <tabs>" & vbCrLf
     strXML &= "      <tab idMso=""TabHomeAccess"">" & vbCrLf
     strXML &= "        <group id=""grpFastSearch"" label=""Schnellsuche"" insertAfterMso=""GroupSortAndFilter"">" _
         & vbCrLf
     strXML &= "          <box id=""box1"">" & vbCrLf
     strXML &= "            <editBox label=""Filtern nach:"" id=""txtFilter"" sizeString=""aaaaaaaaaaaaaaaaa"" " _
         & "onChange=""onChange"" getText=""getText""/>" & vbCrLf
     strXML &= "            <button imageMso=""FilterToggleFilter"" id=""btnFilter"" onAction=""onAction""/>" & vbCrLf
     strXML &= "            <button imageMso=""FilterClearAllFilters"" id=""btnFilterAus"" onAction=""onAction""/>" _
         & vbCrLf
     strXML &= "          </box>" & vbCrLf
     strXML &= "          <checkBox label=""Kompletten Feldinhalt untersuchen"" id=""chkKompletterFeldinhalt"" " _
         & "onAction=""OnAction_Checkbox""/>" & vbCrLf
     strXML &= "          <checkBox label=""Nur aktuelles Feld untersuchen"" id=""chkNurAktuellesFeldUntersuchen"" " _
         & "onAction=""OnAction_Checkbox""/>" & vbCrLf
     strXML &= "        </group>" & vbCrLf
     strXML &= "      </tab>" & vbCrLf
     strXML &= "    </tabs>" & vbCrLf
     strXML &= "  </ribbon>" & vbCrLf
     strXML &= "</customUI>" & vbCrLf
     Return strXML
End Function

Listing 1: Zusammenstellen der Ribbondefinition

Diese nimmt einen Verweis auf die Ribbondefinition entgegen und speichert diese in der Variablen objRibbon:

Function OnLoad(ribbon As IRibbonUI)
     Set objRibbon = ribbon
End Function

Die für das Attribut loadImage hinterlegte Funktion loadImage erwartet für den mit imageId übergebenen Namen ein entsprechendes Objekt des Typs IPictureDisp. Dieses holen wir mit der Funktion LoadResPicture aus den Ressourcen des twinBASIC-Projekts:

Function LoadImage(imageId As String) As IPictureDisp
     Return LoadResPicture(imageId, _
        vbResBitmapFromIcon, 32, 32)
End Function

In diesem COM-Add-In nutzen wir diese Funktion ehrlich gesagt gar nicht – aber wenn Sie weitere Funktionen hinzufügen wollen, deren Schaltflächen ein benutzerdefiniertes Icon aufweisen sollen, fügen Sie einfach die entsprechende .ico-Datei zum Ordner Resources|ICON des Projekts hinzu und hinterlegen den Namen für die Eigenschaft image des jeweiligen Ribbonelements.

In der Ribbondefinition geht es weiter mit den Elementen ribbon, tabs und tab. Als tab-Element referenzieren wir das eingebaute tab-Element TabHomeAccess. Hier fügen wir ein group-Element ein, das wir hinter dem eingebauten Element GroupSortAndFilter platzieren, also direkt hinter den standardmäßigen Sortier- und Filterfunktionen. Darin legen wir ein box-Element an, dass die editBox namens txtFilter und die beiden button-Elemente btnFilter und btnFilterAus gruppieren soll, damit diese in einer Zeile nebeneinander abgebildet werden.

Danach folgen noch die beiden checkBox-Elemente chkKompletterFeldinhalt und chkNurAktuellesFeldUntersuchen. Anschließend werden die geöffneten Elemente group, tab, tabs, ribbon und customUI in umgekehrter Reihenfolge wieder geschlossen.

Funktionen der Steuerelemente im Ribbon

Das editBox-Steuerelement haben wir mit den beiden Attributen onChange und getText ausgestattet. onChange wird ausgelöst, wenn der Benutzer den Inhalt ändert und die Änderung abschließt. Dies löst den folgenden Code aus:

Sub OnChange(control As IRibbonControl, text As String)
     strVergleichswert = text
     Call Filter()
End Sub

Wir schreiben den Vergleichswert in die Variable strVergleichswert und rufen die Prozedur Filter auf, die das Filtern selbst erledigt. Auf diese kommen wir später zurück.

Die durch getText ausgelöste Funktion liefert den aktuellen Wert von strVergleichswert an das editBox-Element zurück:

Function GetText(control As IRibbonControl) As String
     Return strVergleichswert
End Function

Wozu das sinnvoll ist, besprechen wir gleich im Anschluss.

Funktionen der Schaltflächen

Die Schaltfläche btnFilter ruft mit onAction die Prozedur onAction auf, die wie folgt aussieht:

Public Sub OnAction(control As IRibbonControl)
     Select Case control.Id
         Case "btnFilter"
             Call Filter
         Case "btnFilterAus"
             strVergleichswert = ""
             Call objRibbon.Invalidate()
             Call Filter
         Case Else
             MsgBox "OnAction nicht behandelt: " & control.Id
     End Select
End Sub

Sie erwartet mit dem Parameter control einen Verweis auf das aufrufende button-Element. Wenn wir den Button btnFilter anklicken, sorgt dies für den Aufruf der Prozedur Filter.

Wenn wir btnFilterAus anklicken, wird strVergleichswert auf eine leere Zeichenkette eingestellt. Außerdem rufen wir die Methode Invalidate von objRibbon auf und sorgen so dafür, dass alle get…-Attribute erneut aus den entsprechenden Funktionen gefüllt werden müssen.

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