Die Konstellation von Haupt- und Unterformular zur Darstellung von Daten aus 1:n- beziehungsweise m:n-Beziehungen ist bekannt. Einen Datensatz im Hauptformular zu suchen ist auch kein Hexenwerk. Aber wie sieht es aus, wenn wir das Hauptformular nach den Datensätzen filtern wollen, deren verknüpfte Tabelle einen Datensatz mit einem bestimmten Kriterium enthält Und wenn wir dann noch einen Schritt weitergehen und noch den ersten passenden Datensatz im Unterformular markieren wollen Wie dies gelingt, zeigt der vorliegende Beitrag.
Die Tabellen der Beispieldatenbank rekrutieren sich wieder eimal aus der Südsturm-Datenbank, unserer angepassten Nordwind-Variante. Im ersten Beispiel schauen wir uns die Kategorien im Hauptformular an und die Artikel einer jeden Kategorie im Unterformular.
Mit einem Suchfeld im Hauptformular wollen wir nach Artikeln filtern. Außerdem soll es zwei Schaltflächen geben, mit denen wir zwischen den Ergebnissen hin- und herblättern können. Das Formular soll dann wie in Bild 1 aussehen.
Bild 1: Formular mit Filter nach Artikelname, Variante I
Aufbau des Formulars
Das Hauptformular verwendet die Tabelle tblKategorien als Datenherkunft und zeigt die beiden Felder KategorieID und Kategoriename an. Das Unterformular steuert die Daten der Tabelle tblArtikel bei, und zwar in der Daten-blatt-ansicht. Damit es jeweils nur die Datensätze anzeigt, die mit dem aktuellen Datensatz der Tabelle tblKategorien im Hauptformular verknüpft sind, erhalten die Eigenschaften Verknüpfen von und Verknüpfen nach des Unterformular-Steuerelements jeweils den Wert KategorieID.
Steuerelemente
Die zusätzlichen Steuerelemente im Formular heißen txtSuchbegriff, cmdVorheriger und cmdNaechster. Wenn der Benutzer einen Begriff in das Textfeld txtSuchbegriff eingibt, soll die erste Kombination aus Kategorie und Artikel gefunden werden, deren Artikelname dem im Suchfeld eingegebenen Ausdruck entspricht (Platzhalter wie das Sternchen (*) sind dabei erlaubt).
Die beiden Schaltflächen cmdVorheriger und cmdNaechster sind beim Laden des Formulars noch deaktiviert. Erst, wenn der Benutzer einen Suchbegriff eingibt, wird geprüft, ob eine der Schaltflächen aktiviert werden soll – oder auch beide. Zeigt das Formular den ersten Treffer an und gibt es noch einen weiteren, soll die Schaltfläche cmdNaechster aktiviert werden. Blättert der Benutzer damit zum folgenden Treffer, soll auch die Schaltfläche cmdVorheriger aktiviert werden. Die Schaltfläche cmdNaechster bleibt dabei verfügbar, bis der Benutzer zum letzten Ergebnis weitergeklickt hat.
Programmierung der Suche
Die Suchfunktion erfordert einen etwas anderen Ansatz als übliche Suchfunktionen. Direkt nach der Eingabe des Suchbegriffs erstellen wir ein Recordset, das die Tabelle tblArtikel aufnimmt – mit dem eingegebenen Suchbegriff als Vergleichswert für das Feld Artikelname. Die Tabelle liefert für jedes Suchergebnis sowohl die ArtikelID also auch die KategorieID aus dem entsprechenden Fremdschlüsselfeld. Damit können wir dann also sowohl den gesuchten Datensatz im Unterformular einstellen als auch die dazu passende Kategorie im Hauptformular.
Schaltflächen deaktivieren
Beim Laden des Formulars sollen die beiden Schaltflächen cmdVorheriger und cmdNaechster zunächst deaktiviert sein. Dazu legen wir für das Ereignis Beim Laden die folgende Ereignisprozedur an:
Private Sub Form_Load() Me!cmdVorheriger.Enabled = False Me!cmdNaechster.Enabled = False End Sub
Nach der Eingabe eines Suchbegriffes und dem Auslösen des Ereignisses Nach Aktualisierung soll die Prozedur aus Listing 1 ausgelöst werden. Die Prozedur füllt die Variable db mit einem Verweis auf das Database-Objekt der aktuellen Datenbank. Dann liest sie den Suchbegriff aus dem Textfeld txtSuchbegriff in die Variable strSuchbegriff ein. Hat der Suchbegriff eine Länge von mehr als null Zeichen, erstellt die Prozedur ein neues Recordset, das alle Datensätze der Tabelle tblArtikel enthält, deren Feld Artikelname dem Suchbegriff entspricht. Dieses Recordset speichert die Prozedur in einer Variablen, die im Kopf des Klassenmoduls wie folgt deklariert wird und damit von allen Prozeduren des Moduls aus erreichbar ist:
Private Sub txtSuchbegriff_AfterUpdate() Dim db As DAO.Database Dim strSuchbegriff As String Set db = CurrentDb strSuchbegriff = Nz(Me!txtSuchbegriff, "") If Len(strSuchbegriff) > 0 Then Set rstErgebnis = db.OpenRecordset("SELECT ArtikelID, KategorieID FROM tblArtikel WHERE Artikelname LIKE ''" _ & strSuchbegriff & "'' ORDER BY tblKategorien.KategorieID, tblArtikel.ArtikelID", dbOpenSnapshot) SteuerelementeAktualisieren Filtern Else FilterAufheben End If End Sub
Listing 1: Prozedur für das Ereignis Nach Aktualisierung des Suchfeldes
Dim rstErgebnis As DAO.Recordset
Wir verwenden den Wert dbOpenSnapshot als Parameter, da dies direkt den Wert der Eigenschaft Recordcount des Recordsets verfügbar macht. Nachdem dies geschehen ist, ruft die Prozedur zwei weitere Routinen namens SteuerelementeAktualisieren und Filtern auf. Erstere aktiviert oder deaktiviert die beiden Schaltflächen cmdVorheriger und cmdNaechster in Abhängigkeit von der Datensatzposition, der zweite filtert die Daten in Haupt- und Unterformular nach dem aktuellen Datensatz des Recordsets rstErgebnis.
Sollte das Textfeld txtSuchbegriff keinen Wert enthalten, ruft die Prozedur die Routine FilterAufheben auf, was wieder alle Datensätze in Haupt- und Unterformular anzeigt.
Steuerelemente aktualisieren
Die Routine SteuerelementeAktualisieren kümmert sich um das Aktivieren und Deaktivieren der beiden Schaltflächen cmdVorheriger und cmdNaechster. Die erste If…Then-Bedingung dieser Routine prüft, ob die aktuelle Position des Datensatzzeigers von rstErgebnis kleiner als die Anzahl der Datensätze minus eins ist.
Minus eins deshalb, weil AbsolutePosition für den ersten Datensatz den Wert 0 liefert. In diesem Fall aktiviert die Routine die Schaltfläche cmdNaechster, anderenfalls wird sie deaktiert. Bei der Schaltfläche cmdVorheriger sieht es ähnlich aus: Die If…Then-Bedingung prüft, ob AbsolutePosition größer 0 ist. Falls ja, kann der Benutzer noch einen Datensatz nach vorn blättern und die Schaltfläche cmdVorheriger wird aktiviert:
Private Sub SteuerelementeAktualisieren() If rstErgebnis.AbsolutePosition _ < rstErgebnis.RecordCount - 1 Then Me!cmdNaechster.Enabled = True Else Me!cmdNaechster.Enabled = False End If If rstErgebnis.AbsolutePosition > 0 Then Me!cmdVorheriger.Enabled = True Else Me!cmdVorheriger.Enabled = False End If End Sub
Filtern der Artikel
Die Routine Filtern sorgt für die Anzeige des jeweils aktuellen Datensatzes des Recordsets rstErgebnis (s. Listing 2). Dabei prüft die Routine zunächst, ob das Recordset mindestens einen Datensatz enthält. Falls ja, stellt sie die Eigenschaft Filter des Hauptformulars auf einen Ausdruck ein, bei dem der Wert von KategorieID der Datenherkunft dem Wert dieses Feldes im aktuelle Datensatz des Recordsets entspricht und aktiviert den Filter durch Setzen von FilterOn auf True.
Private Sub Filtern() If Not rstErgebnis.RecordCount = 0 Then With Me .Filter = "KategorieID = " & rstErgebnis!KategorieID .FilterOn = True End With With Me!sfmArtikelNachKategorie.Form .Filter = "ArtikelID = " & rstErgebnis!ArtikelID .FilterOn = True End With Else With Me .Filter = "1=2" .FilterOn = True End With End If End Sub
Listing 2: Prozedur zum Filtern der Daten in Haupt- und Unterformular
Auf die gleiche Weise filtert es das Unterformular so, dass nur der Artikel aus dem aktuellen Datensatz des Recordsets erscheint. Liefert rstErgebnis keinen Datensatz, stellt die Prozedur den Filter für das Hauptformular auf den Ausdruck 1=2 ein, was keine Datensätze liefert. Dementsprechend bleibt auch das Unterformular leer.
Aufheben des Filters
Leert der Benutzer das Textfeld strSuchbegriff und löst das Ereignis Nach Aktualisierung des Textfeldes aus, ruft die Prozedur txtSuchbegriff_AfterUpdate wie oben erwähnt die Prozedur FilterAufheben auf.
Diese leert die Eigenschaft Filter sowohl des Unterformulars als auch des Hauptformulars. Dabei ist die Reihenfolge wichtig – Sie müssen erst den Filter im Unterformular aufheben und dann den im Hauptformular, anderenfalls zeigt das Formular die Datensätze im Unterformular nicht korrekt an:
Private Sub FilterAufheben() Me!sfmArtikelNachKategorie.Form.Filter = "" Me.Filter = "" Set rstErgebnis = Nothing Me!cmdVorheriger.Enabled = False Me!cmdNaechster.Enabled = False End Sub
Außerdem leert die Prozedur das Recordset rstErgebnis und deaktiviert die Schaltflächen cmdVorheriger und cmdNaechster.
Funktion der Schaltflächen
Die Schaltfläche cmdNaechster soll beim Anklicken das nächste Suchergebnis liefern, also den folgenden Datensatz der Recordsets rstErgebnis. Dazu bewegt die Prozedur den Datensatzzeiger mit der Methode MoveNext zum folgenden Datensatz und ruft dann die beiden Routinen SteuerelementeAktualisieren und Filtern auf, um sowohl die Aktivierung der Steuerelemente zu prüfen als auch Haupt- und Unterformular nach dem aktuellen Suchergebnis zu filtern:
Private Sub cmdNaechster_Click() rstErgebnis.MoveNext SteuerelementeAktualisieren Filtern End Sub
Die Prozedur, die durch einen Klick auf die Schaltfläche cmdVorheriger ausgelöst wird, erledigt die gleiche Aufgabe, springt aber zum vorherigen Datensatz des Recordsets mit den Suchergebnissen:
Private Sub cmdVorheriger_Click() rstErgebnis.MovePrevious SteuerelementeAktualisieren Filtern End Sub
Die Prozeduren sorgen in dieser Form dafür, dass Haupt- und Unterformular jeweils nur einen Datensatz anzeigen. Das mag für bestimmte Anwendungszwecke passen, aber nicht für alle – also stellen wir eine Alternative vor.
Variante II: Suchergebnis aktivieren statt filtern
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