Wenn man Daten aus einer Liste nach verschiedenen Kriterien filtern möchte, kann man gar nicht genug Komfort haben. In diesem Beitrag stellen wir Ihnen eine Lösung vor, mit der Sie in einem Unterformular in der Datenblattansicht suchen können – und zwar mit allen Finessen. Das heißt, dass Sie entweder zuerst alle Suchparameter eingeben und dann die Suche anstoßen können oder auch gleich mit Eingabe eines jeden Zeichens ein aktualisiertes Suchergebnis erhalten. Oder dass Sie entscheiden können, ob die Daten nur nach genauen Treffern durchsucht werden sollen.
Es gibt verschiedene Ansätze, wie sich Suchfunktionen in Datenbankanwendungen implementieren lassen. Einige finden direkt in dem Formular Platz, das auch die zu durchsuchenden Daten anzeigt, andere erscheinen als eigenes Formular, das auch gleich die Suchergebnisse präsentiert. In unserem Fall soll die Übersichtsliste der zu durchsuchenden Daten in einem Formular und das Suchformular als Popup-Formular erscheinen. Auf diese Weise können Sie das Formular mit den Suchkriterien an beliebiger Stelle platzieren, die Suchbegriffe eingeben, ändern oder entfernen und zu jeder Zeit das Suchergebnis aktualisieren lassen. Im Detail sieht das wie in Bild 1 aus.
Bild 1: Suchformular und zu durchsuchende Daten im Überblick
Funktionen des Suchformulars
Der Benutzer soll beliebige Suchbegriffe in die Suchfelder eingeben können. Kombinationsfelder dienen zur direkten Auswahl von Suchbegriffen – im Beispiel etwa die Anrede, für die es nur zwei Möglichkeiten gibt. Bei der Eingabe der Suchbegriffe kann der Benutzer entweder erst alle gewünschten Suchbegriffe in die Textfelder eingeben beziehungsweise aus den Kombinationsfeldern auswählen und dann die Suche mit einem Klick auf die Schaltfläche Suchen starten. Oder er aktiviert die Option Schnellsuche oben im Formularkopf: Dann führt die Eingabe eines jeden Zeichens und die Auswahl eines jeden Kombinationsfeldeintrags zur Anzeige der gefundenen Einträge in der zu durchsuchenden Liste.
Eine weitere Option legt fest, ob die Textfelder nur nach genauen Treffern durchsucht werden sollen (Andre zeigt dann nur Datensätze mit Andre, aber keine mit Andreas an), ob auch Treffer ausgegeben werden sollen, die mit dem eingegebenen Suchbegriff beginnen oder ob das Suchergebnis sogar solche Treffer liefern soll, bei denen der Suchbegriff irgendwo im Text enthalten ist (An liefert dann sowohl Andre als auch Hermann).
Die Schaltfläche Leeren soll alle Suchbegriffe wieder auf den Anfangszustand zurücksetzen, die Schaltfläche Abbrechen schließt den Dialog.
Aufruf des Suchformulars
Das Formular mit dem zu durchsuchenden Datenblatt wird mit einer Schaltfläche namens cmdSuchen ausgestattet, die folgende Ereignisprozedur auslöst:
Private Sub cmdSuche_Click() DoCmd.OpenForm "frmKundensuche", OpenArgs:="sfmKundenuebersicht" End Sub
Dies öffnet das Formular namens frmKundensuche und übergibt den Namen des zu durchsuchenden Unterformulars als Öffnungsargument. Die Programmierung der hier verwenden Kundenübersicht finden Sie im Beitrag Programmierung der KVA (www.access-im-unternehmen.de/857).
Anlegen des Suchformulars
Das Suchformular sieht im Entwurf wie in Bild 2 aus. Es enthält alle Felder, die Sie auch im Unterformular mit den zu durchsuchenden Daten finden, nämlich die Felder der Tabelle tblKundenBase der Beispielanwendung KVA.mdb.
Bild 2: Entwurf des Suchformulars
Die Suchfelder sollen Namen erhalten, die aus dem Feldnamen und einem Präfix bestehen – txt für Textfelder und cbo für Kombinationsfelder. Die Bezeichnungsfelder weisen auf den Inhalt des jeweils zu durchsuchenden Feldes hin. Wenn Sie die Felder nicht alle von Hand anlegen möchten, können Sie dies mit einem kleinen Trick erledigen. Stellen Sie dazu die Datenherkunft eines leeren Formulars auf die Tabelle ein, welche die zu durchsuchenden Daten enthält – hier tblKundenBase – und ziehen Sie alle benötigten Felder aus der Feldliste in den Detailbereich des Formulars (s. Bild 3).
Bild 3: Anlegen der Suchfelder
Danach passen Sie, sofern die Eigenschaft Beschriftung der Felder im Tabellenentwurf nicht bereits mit entsprechenden Beschriftungen versehen war, die Beschriftungsfelder an (zum Beispiel von EMail zu E-Mail).
Nun versehen Sie die Eigenschaftsnamen noch mit entsprechenden Präfixen, also txt für die Textfelder und cbo für die als Nachschlagefelder ausgelegten Suchfelder. Sie können das manuell erledigen oder Sie nutzen das Add-In Control Renamer, das im Beitrag Access-Add-Ins (www.access-im-unternehmen.de/643) vorgestellt wird. Damit können Sie die Steuerelemente mit einem Mausklick um das gewünschte Präfix erweitern. Achtung: Dies gelingt nur, solange die Steuerelemente noch gebunden sind – erledigen Sie dies also vor dem folgenden Schritt, wenn Sie den Control Renamer einsetzen möchten.
Nun benötigen wir allerdings keine gebundenen Felder, sondern nur einfache Textfelder. Glücklicherweise können Sie Eigenschaften immer für mehrere Steuerelemente gleichzeitig ändern. Also markieren Sie durch Aufziehen eines entsprechenden Rahmens alle Textfelder und kümmern sich um die Eigenschaft Steuerelementinhalt. Diese wird bereits als leer angezeigt, aber nur, weil die Eigenschaft für alle markierten Steuerelemente unterschiedliche Werte aufweist. Wie aber leeren wir eine bereits als leer dargestellte Eigenschaft Ganz einfach: Sie tippen ein beliebiges Zeichen in die Eigenschaft, was alle vorhandenen Werte überschreibt, und löschen dieses wieder. Nun ist die Eigenschaft Steuerelement tatsächlich leer, wie die Kontrolle der Eigenschaft für ein einzelnes Steuerelement belegt.
Anpassen der Kombinationsfelder
Die Kombinationsfelder cboAnredeID und cboPersoenlicheAnredeID bieten, wenn Sie die entsprechenden Felder der Tabelle tblKundenBase als Nachschlagefelder eingerichtet haben, alle Datensätze der zugrunde liegenden Tabellen zur Auswahl an. Um den Komfort der Suchfunktion zu erhöhen, sollen diese gleich beim Anzeigen des Suchformulars Einträge wie <Alle> anzeigen. Dazu passen wir die Datensatzherkunft der beiden Steuerelemente etwas an. Für das Steuerelement cboAnredeID hinterlegen Sie hier den folgenden Ausdruck:
SELECT 0 AS AnredeID, ''<Alle>'' AS Anrede FROM tblAnreden UNION SELECT AnredeID, Anrede FROM tblAnreden;
Der Ausdruck für die Eigenschaft Datensatzherkunft des Steuerelements cboPersoenlicheAnredeID ist ähnlich aufgebaut:
SELECT 0 as PersoenlicheAnredeID, ''<Alle>'' AS PersoenlicheAnrede FROM tblPersoenlicheAnreden UNION SELECT PersoenlicheAnredeID, PersoenlicheAnrede FROM tblPersoenlicheAnreden;
Weitere Steuerelemente
Fügen Sie dem Formular nun die übrigen Steuerelemente hinzu:
- Kontrollkästchen mit dem Namen chkSchnellsuche und der Beschriftung Schnellsuche
- Optionsgruppe namens ogrSuchoptionen und drei Optionen mit den Beschriftungen Nur genaue Treffer (Wert 1), Text beginnt mit … (Wert 2) und Text enthält … (Wert 3)
- Schaltfläche cmdSuchen mit der Beschriftung Suchen
- Schaltfläche cmdLeeren mit der Beschriftung Leeren
- Schaltfläche cmdAbbrechen mit der Beschriftung Abbrechen
Programmierung der Suchfunktion
Bei den folgenden Ausführungen ist es wichtig zu wissen, dass das Suchformular dafür konzipiert ist, von einem anderen Formular per Schaltfläche geöffnet zu werden. Außerdem muss dieses Formular das Unterformular in der Datenblattansicht enthalten, dessen Datensätze mithilfe des Suchformulars gefiltert werden sollen.
Es gibt also eine Interaktion zwischen dem aufrufenden Formular sowie dem aufgerufenen Suchformular – nicht nur in einer Richtung:
- Das Suchformular soll die Daten im aufrufenden Formular aktualisieren, wenn der Benutzer die Suche startet.
- Andersherum soll das Suchformular geschlossen werden, wenn der Benutzer das zu durchsuchende Formular schließt, ohne das Suchformular vorher geschlossen zu haben.
Für diese Interaktion benötigt das Suchformular einen Verweis auf das Hauptformular. Diesen speichert das Suchformular in einer Variablen namens frmParent. Damit das Suchformular auf das Schließen des zu durchsuchenden Formulars reagieren kann, wird diese Objektvariable mit dem Schlüsselwort WithEvents deklariert:
Private WithEvents frmParent As Form
Um das im aufrufenden Formular enthaltene Unterformular in der Datenblattansicht aktualisieren beziehungsweise filtern zu können, benötigen wir auch einen Verweis auf dieses Element.
Dieses speichern wir in der folgenden Variable – WithEvents ist hier nicht nötig, da wir nicht auf Ereignisse im Unterformular reagieren müssen:
Private frmDataSheet As Form
Damit kommen wir zu der Prozedur, die durch das Ereignis Beim Öffnen des Formulars ausgelöst wird und wie in Listing 1 aussieht.
Listing 1: Die Prozedur, die durch das Ereignis Beim Öffnen ausgeführt wird
Private Sub Form_Open(Cancel As Integer) Dim ctl As control If IsNull(Me.OpenArgs) Then MsgBox "Das Suchformular kann nur von einem Formular mit zu durchsuchendem Unterformular " _ & "geöffnet werden. Dessen Name ist als Öffungsargument zu übergeben." Cancel = True Else Set ctl = Screen.ActiveControl Set frmParent = ctl.Parent frmParent.OnUnload = "[Event Procedure]" Set frmDataSheet = frmParent(Me.OpenArgs).Form End If End Sub
Die Prozedur hat zunächst die Aufgabe, das Formular sofort mit einer entsprechenden Meldung wieder zu schließen, wenn dieses über einen anderen Weg als über die dafür vorgesehene Schaltfläche geöffnet wird. Dazu prüft die Prozedur zunächst, ob beim Aufruf des Formulars mit der DoCmd.OpenForm-Methode ein Öffnungsargument übergeben wurde.
Ist dies der Fall, holt sich die Prozedur zunächst einen Verweis auf das Steuerelement, das beim Aufrufen des Formulars aktiv ist – in diesem Fall also die Schaltfläche cmdSuchen des zu durchsuchenden Formulars.
Dieses Steuerelement wiederum hat eine Parent-Eigenschaft, die auf das Form-Objekt verweist, in dem sich die Schaltfläche befindet. Ein Verweis auf dieses Formular landet in der bereits erwähnten Variablen objParent.
Das mit Me.OpenArgs abgefragte Öffnungsargument liefert den Namen des zu durchsuchenden Unterformulars, zu dem sich die Prozedur mit frmParent(Me.OpenArgs).Form ebenfalls einen Verweis holt und diesen diesmal in der Variablen frmDataSheet speichert.
Für das in frmParent gespeicherte Formular soll eine Ereignisprozedur im Klassenmodul des Formulars frmKundensuche implementiert werden, das durch das Ereignis Beim Entladen ausgelöst wird. Dies gibt die Prozedur Form_Open mit der folgenden Zeile zunächst bekannt:
frmParent.OnUnload = "[Event Procedure]"
Die Implementierung der Ereignisprozedur sieht schließlich so aus:
Private Sub frmParent_Unload(Cancel As Integer) DoCmd.Close acForm, Me.Name End Sub
Damit haben wir zwar noch keine Suchfunktion programmiert, aber zumindest ist sichergestellt, dass das Suchformular zusammen mit dem aufrufenden Formular auch wieder geschlossen wird. Dies könnte nämlich wiederum zu Problemen führen, wenn der Benutzer das Suchformular noch einsetzt, obwohl das zu durchsuchende Formular längst geschlossen ist.
Kommen wir nun zur Ereignisprozedur, die durch das Ereignis Beim Laden des Steuerelements ausgelöst wird.
Dies sieht wie in Listing 2 aus und enthält für den aktuellen Zeitpunkt nur zwei wichtige Anweisungen – nämlich diejenigen, welche die Werte der beiden Kombinationsfelder cboAnredeID und cboPersoenlicheAnredeID auf den jeweils ersten Eintrag einstellen – also auf <Alle>. Auf die übrigen Anweisungen kommen wir im späteren Verlauf zurück.
Listing 2: Die Prozedur, die durch das Ereignis Beim Laden ausgeführt wird
Private Sub Form_Load() Dim objSuchformularControl As clsSuchformularControl Set colSuchformularsteuerelemente = New Collection Me!cboAnredeID = Me!cboAnredeID.ItemData(0) Me!cboPersoenlicheAnredeID = Me!cboPersoenlicheAnredeID.ItemData(0) Dim ctl As control For Each ctl In Me.Controls Select Case ctl.ControlType Case acTextBox, acComboBox Set objSuchformularControl = New clsSuchformularControl With objSuchformularControl Set .SearchControl = ctl End With colSuchformularsteuerelemente.Add objSuchformularControl End Select Next ctl End Sub
Aufrufen der Suchfunktion
Das Programmieren der Suchfunktion wäre einfach, wenn diese nur über die Schaltfläche cmdSuchen gestartet werden könnte (beziehungsweise das Betätigen der Eingabe-Taste – durch Einstellen der Eigenschaft Standard der Schaltfläche cmdSuchen auf den Wert Ja löst auch die Eingabe-Taste die Ereignisprozedur cmdSuchen_Click aus).
Aber um die Suche noch etwas komfortabler zu gestalten, haben wir entschieden, dass der Benutzer durch Aktivieren der Option Schnellsuche dafür sorgen kann, dass die Suche nach der Eingabe eines jeden Zeichens in eines der Textfelder beziehungsweise der Auswahl eines Eintrags der Kombinationsfelder erneut durchgeführt werden soll.
Damit ergeben sich kleinere Probleme: Wenn Sie nämlich beispielsweise einen Buchstaben in das Textfeld txtVorname eingeben, soll der Filter entsprechend zusammengestellt werden (etwa Vorname LIKE “A“). Dazu muss die Prozedur, die den Filterausdruck zusammenstellt, den im Suchfeld angegebenen Text einlesen. Dies gelingt, ohne die Eingabe in das Textfeld abzuschließen, nur über die Text-Eigenschaft des Textfeldes. Bei Feldern, die gerade nicht bearbeitet werden, reicht das Abfragen der Value-Eigenschaft aus.
In der Schleife, die alle Steuerelemente durchläuft, um den Filterausdruck zusammenzustellen, müssten wir also auch noch prüfen, ob das aktuell durchlaufene Steuerelement eventuell gerade in Bearbeitung ist, und dementsprechend entweder auf die Value– oder die Text-Eigenschaft zugreifen, um den aktuellen Inhalt des Steuerelements zu ermitteln.
Da dies sehr unpraktisch ist, sorgen wir dafür, dass der Inhalt der Textfelder nach jeder änderung in der sonst nicht verwendeten Eigenschaft Tag gespeichert wird. Dazu müssten wir nun für jedes Textfeld eine Ereignisprozedur anlegen, die beispielsweise wie folgt aussieht:
Private Sub txtVorname_Change() txtVorname.Tag = txtVorname.Text If Me!chkSchnellsuche Then Suchen End If End Sub
Die Prozedur trägt den aktuellen Text des Textfeldes (nicht zu verwechseln mit dem Wert) in die Eigenschaft Tag ein. Außerdem prüft sie, ob die Option chkSchnellsuche aktiviert ist, und ruft gleich noch die Prozedur Suchen auf, um das Suchergebnis zu aktualisieren (mehr zu dieser Prozedur weiter unten).
Nun macht es erstens keinen Spaß, für jedes Steuerelement eine solche Prozedur anzulegen, und zweitens müssen Sie dies für eventuell hinzukommende Steuerelemente auch noch jedesmal wiederholen. Also programmieren wir eine kleine Klasse namens clsSuchformularControl, die jeweils den Verweis auf eines der Steuerelemente speichert und auch noch die oben beschriebene Ereignisprozedur enthält, die den Suchbegriff zwischenspeichert und die Suchfunktion aufruft.
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