Dieser Artikel ist Teil des Magazins 'Access im Unternehmen', Ausgabe 6/2017.
Unterdatenblätter in Formularen
Unterdatenblätter in Tabellen oder Abfragen kennen Sie sicherlich bereits. Das sind die Bereiche einer Datenblattansicht, die aufklappen, wenn Sie das Plus-Zeichen vor einem Datensatz anklicken. Wenn Sie eine Tabelle, für die eine solche Unterdatenblatt-Funktion eingerichtet ist, jedoch in der Datenblattansicht in einem Formular oder Unterformular anzeigen wollen, verschwinden die praktischen Plus-Zeichen und Sie schauen in die Röhre. Doch das ist nicht das Ende der Fahnenstange: Access sieht durchaus den Einsatz von Unterdatenblättern in Formularen vor – und damit lässt sich eine Menge anstellen!
Als Beispiel verwenden wir die beiden Tabellen tblTabellen und tblFelder der Lösung aus dem Beitrag Daten anonymisieren (www.access-im-unternehmen.de/1112). Dabei handelt es sich um zwei Tabellen, von denen die erste alle Tabellennamen einer Datenbank speichern soll und die zweite alle in den Tabellen enthaltenen Felder. Dabei enthält die zweite Tabelle tblFelder ein Fremdschlüsselfeld, mit dem ein Datensatz der Tabelle tblTabellen ausgewählt werden kann, um die Zugehörigkeit des Feldes zu einer Tabelle zu definieren.
Wenn Sie die dortige Tabelle tblTabellen mit einigen Beispieldaten wie hier aus der Südsturm-Datenbank öffnen, erscheinen direkt die Plus-Zeichen, mit denen sich die untergeordneten Datensätze der verknüpften Tabelle tblFelder einblenden lassen (s. Bild 1).
Bild 1: Tabelle mit UnterdatenblattWarum benötigen wir diese Ansicht? In diesem Fall wollen wir es uns ersparen, ein TreeView-Steuerelement für die Anzeige der hierarchisch verknüpften Daten der beiden Tabellen tblTabellen und tblFelder hinzuzuziehen. Stattdessen wollen wir einmal das oft verschmähte Feature Unterdatenblatt nutzen. In der Lösung, die diese Ansicht nutzen soll, wollen wir die Möglichkeit haben, sowohl Einträge der übergeordneten Tabelle als auch die der untergeordneten Tabelle auszuwählen und abzuwählen. Wie die Abbildung zeigt, könnte man damit schon recht komfortabel die Daten mit den dazu eingerichteten Ja/Nein-Feldern zugreifen. Allerdings wollen wir dort noch einen Schritt weiter gehen: Wenn der Benutzer das Ja/Nein-Feld einer Tabelle selektiert, sollen automatisch alle Einträge der untergeordneten Tabelle mit den Feldern ausgewählt werden. Andersherum soll das Ja/Nein-Feld für eine Tabelle abgewählt werden, wenn der Benutzer nur eines der untergeordneten Felder abwählt. Und wenn der Benutzer das Ja/Nein-Feld für eine Tabelle abwählt, sollen auch alle zu der Tabelle gehörenden Felder abgewählt werden.
Unterdatenblatt im Formular
Wie aber bekommen wir diese Ansicht in das Unterformular eines Formulars? Der erste und einfachere Ansatz ist der folgende: Sie fügen dem Formular ein Unterformular-Steuerelement hinzu. Dann stellen Sie für die Eigenschaft Herkunftsobjekt des Unterformular-Steuerelements den Wert Tabelle.tblTabellen ein (s. Bild 2).
Bild 2: Einrichten eines Unterformulars mit Tabelle plus UnterdatenblattWechseln Sie nun in die Formularansicht des Formulars, erhalten Sie die Ansicht aus Bild 3. Das ist ja schon fast genau das, was wir wollen! Aber Moment: Vielleicht bekommen wir noch irgendwie das Feld TabelleID der übergeordneten Tabelle und die Felder FeldID und Felddatentyp der untergeordneten Tabelle weg?
Bild 3: Unterformular mit Tabelle plus UnterdatenblattAuch das gelingt uns, indem wir einfach mit der rechten Maustaste auf die Spaltenköpfe der zu entfernenden Felder klicken und diese mit dem Befehl Felder ausblenden des Kontextmenüs verschwinden lassen. Das Ergebnis sehen sie in Bild 4. Nun müssen wir nur noch ein paar Ereignisprozeduren für die Ja/Nein-Felder namens Anonymisieren der Tabellen tblTabellen und tblFelder hinterlegen, mit denen wir die gewünschten und oben erwähnten Funktionen hinterlegen können. Und hier verlässt uns diese einfache Variante dann doch: Da wir als Herkunftsobjekt des Unterformulars eine Tabelle angegeben haben, können wir dafür keine Ereignisse hinterlegen. Dies funktioniert nur, wenn Sie ein Formular mit den entsprechenden Steuerelementen anlegen. Ist unser Plan, die Daten über die Unterdatenblätter anzuzeigen, gescheitert? Nein, wir haben noch eine Alternative!
Bild 4: Unterdatenblatt mit ausgeblendeten Feldern
Unterdatenblatt per Unterformular
Wir können die Daten nämlich auch als echtes Unterformular abbilden. Dazu erstellen Sie als Erstes ein Unterformular namens sfmTabellen. Diesem weisen Sie als Datenherkunft die Tabelle tblTabellen zu. Ziehen Sie dann alle benötigten Felder in den Formularentwurf. Wir wollen nur die beiden Felder Anonymisieren (das Ja/Nein-Feld) und das Feld Tabellenname verwenden. Wir ziehen zuerst das Ja/Nein-Feld in den Entwurf, da dieses in der ersten Spalte angezeigt werden soll (s. Bild 5).
Bild 5: Erstellen des Unterformulars mit den Daten der Tabelle tblTabellenAußerdem stellen wir die Eigenschaft Standardansicht auf den Wert Datenblatt ein. Ein Wechsel in die Entwurfsansicht liefert allerdings nicht das erwartete Ergebnis – es erscheinen zwar die Daten der Tabelle tblTabellen, aber keine Plus-Zeichen zum Aufklappen der Unterdatenblätter (s. Bild 6).
Bild 6: Kein Unterdatenblatt in Sicht!Kein Wunder: Wir haben bisher auch den entscheidenden Schritt ausgelassen. Wir müssen nämlich auch noch für die Tabelle tblFelder ein Unterformular anlegen und dieses dann als Unterformular zur Datenblattansicht des Unterformulars mit den Tabellen hinzufügen! Speichern wir also zunächst das soeben erstellte Formular unter dem Namen sfmTabellen.
Danach erstellen Sie ein weiteres Unterformular, welches diesmal die Tabelle tblFelder als Datenherkunft verwendet. Davon ziehen Sie die beiden Felder Anonymisieren und Feldname in den Detailbereich der Entwurfsansicht (s. Bild 7).
Bild 7: Unterformular für das UnterdatenblattStellen Sie auch hier die Eigenschaft Standardansicht auf Datenblatt ein. Speichern Sie dieses Unterformular dann unter dem Namen sfmFelder.
Und nun kommt der Clou: Schließen Sie das Unterformular sfmFelder und öffnen Sie das Unterformular sfmTabellen in der Entwurfsansicht. Ziehen Sie dann das Unterformular sfmFelder in den Detailbereich des Entwurfs von sfmTabellen (s. Bild 8).
Bild 8: Unterformular als Unterdatenblatt einfügen
Wechseln Sie nun in die Datenblattansicht des Unterformulars sfmTabellen, erhalten Sie die Ansicht aus Bild 9. Das ist genau, was wir uns vorgestellt haben! Es werden nur die gewünschten Felder angezeigt, sie erscheinen in der richtigen Reihenfolge und wir können die Unterdatenblätter öffnen.
Bild 9: Bingo! Das Unterdatenblatt ist da.Ereignisprozeduren hinzufügen
Nun fehlt nur noch eins: Die Ereignisprozeduren für die Ja/Nein-Felder, welche die jeweils abhängigen Elemente aktivieren oder deaktivieren. Noch einmal zusammengefasst die gewünschten Funktionen:
- Ja/Nein-Feld in tblTabelle wird aktiviert: Alle Untereinträge in tblFelder werden aktiviert.
- Ja/Nein-Feld in tblTabelle wird deaktiviert: Alle Untereinträge in tblFelder werden deaktiviert.
- Ja/Nein-Feld in tblFelder wird aktiviert oder deaktiviert: Wenn alle zum aktuellen Eintrag von tblTabellen gehörenden Untereinträge markiert sind, wird der übergeordnete Eintrag auch markiert. Wenn nicht alle Einträge markiert sind, wird der übergeordnete Eintrag deaktiviert.
Die erste Ereignisprozedur legen wir für das Ja/Nein-Feld Anonymisieren des Unterformulars sfmTabellen an, das wir zuvor in chkAnonymisieren umbenennen. Wir verwenden die Ereignisprozedur Nach Aktualisierung. Die Prozedur heißt chkAnonymisieren_AfterUpdate und sieht wie in Listing 1 aus. Die Prozedur ermittelt zunächst den Primärschlüsselwert des aktuell markierten Datensatzes und speichert diesen in der Variablen lngTabelleID. Dann prüft sie, ob der Benutzer den Wert des Steuerelements chkAnonymisieren soeben auf True oder False eingestellt hat. Im Falle von True stellt die folgende UPDATE-Anweisung den Wert des Feldes Anonymisieren für alle Datensätze der Tabelle tblFelder auf False ein, deren Fremdschlüsselfeld TabelleID mit dem in der Variablen lngTabelleID gespeicherten Wert übereinstimmt. Anderenfalls wird dieser Wert für alle betroffenen Datensätze der Tabelle tblFelder auf den Wert False eingestellt.
Private Sub chkAnonymisieren_AfterUpdate()
Dim db As DAO.Database
Dim lngTabelleID As Long
Set db = CurrentDb
lngTabelleID = Me!TabelleID
If Me!chkAnonymisieren = True Then
db.Execute "UPDATE tblFelder SET Anonymisieren = True WHERE TabelleID = " & lngTabelleID, dbFailOnError
Else
db.Execute "UPDATE tblFelder SET Anonymisieren = False WHERE TabelleID = " & lngTabelleID, dbFailOnError
End If
Me.Dirty = False
End Sub
Listing 1: Ereignisprozedur, die beim Aktivieren oder Deaktivieren eines Datensatzes im Unterformular sfmTabellen ausgelöst wird
Damit sich diese Änderung auch schnell auf die angezeigten Daten in den beiden Unterformularen auswirken, stellen wir anschließend noch die Eigenschaft Dirty auf den Wert False ein und speichern den Datensatz somit.
Die Prozedur, die durch Aktivieren oder Deaktivieren des Wertes des Steuerelements chkAnonymisieren des Unterformulars sfmFelder ausgelöst wird, finden Sie in Listing 2. Diese speichert ebenfalls den Wert des Feldes TabelleID in der Variablen lngTabelleID. Dabei handelt es sich diesmal allerdings nicht um das Primärschlüsselfeld der Tabelle tblTabellen, sondern um das Fremdschlüsselfeld der Tabelle tblFelder. Wenn der Benutzer das Ja/Nein-Feld Anonymisieren auf False eingestellt hat, wir der Wert des gleichnamigen Feldes der übergeordneten Tabelle tblTabellen ebenfalls auf diesen Wert eingestellt. Immerhin ist dadurch mindestens ein untergeordneter Datensatz nicht mehr aktiviert, was auch die Deaktivierung des übergeordneten Datensatzes nach sich ziehen soll.
Private Sub chkAnonymisieren_AfterUpdate()
Dim db As DAO.Database
Dim lngTabelleID As Long
Set db = CurrentDb
lngTabelleID = Me!TabelleID
If Me!chkAnonymisieren = False Then
db.Execute "UPDATE tblTabellen SET Anonymisieren = FALSE WHERE TabelleID = " & lngTabelleID, dbFailOnError
Else
If Nz(DLookup("FeldID", "tblFelder", "Anonymisieren = TRUE AND TabelleID = " & lngTabelleID), 0) = 0 Then
db.Execute "UPDATE tblTabellen SET Anonymisieren = FALSE WHERE TabelleID = " & lngTabelleID, dbFailOnError
Else
db.Execute "UPDATE tblTabellen SET Anonymisieren = TRUE WHERE TabelleID = " & lngTabelleID, dbFailOnError
End If
End If
Me.Dirty = False
End Sub
Listing 2: Ereignisprozedur, die beim Aktivieren oder Deaktivieren eines Datensatzes im Unterformular sfmFelder ausgelöst wird.
Hat der Benutzer hingegen das Ja/Nein-Feld für ein Feld aktiviert, dann müssen wir prüfen, ob er damit dafür gesorgt hat, dass alle Ja/Nein-Felder für die Elemente, die der gleichen Tabelle untergeordnet sind, aktiviert hat oder nicht. Dazu befragen wir die Tabelle tblFelder mit einer DLookup-Funktion, welche den Wert des Feldes FeldID für einen Datensatz ermittelt, dessen Feld TabelleID den Wert aus lngTabelleID und dessen Feld Anonymisieren den Wert False aufweist. Ist ein solcher Datensatz vorhanden, sind nicht alle Felder der Tabelle aktiviert und die Tabelle soll auch als deaktiviert markiert werden. Das erreichen wir wieder mit einer UPDATE-Abfrage, welche den Wert des Feldes Anonymisieren des entsprechenden übergeordneten Datensatzes der Tabelle tblTabellen deaktiviert. Anderenfalls wird dieses Feld im Else-Teil der If...Then-Bedingung deaktiviert.
Feinarbeiten
Das Ergebnis aus Bild 10 sieht bereits recht gut aus. Allerdings stören die Zeilen mit dem leeren, neuen Datensatz ein wenig. Erstens nehmen diese Platz weg und zweitens wollen wir hier auch sicher keine neuen Datensätze hinzufügen. Also nehmen wir uns die Einstellungen vor, die dafür sorgen, dass kein Anfügen eines neuen Datensatzes mehr möglich ist. Dabei handelt es sich jeweils um die Eigenschaft Anfügen zulassen, die wir im übergeordneten und im untergeordneten Unterformular auf den Wert Nein einstellen.
Bild 10: Unterdatenblatt mit VBA-EreignissenDamit erhalten wir das Ergebnis aus Bild 11, mit dem wir prima arbeiten können. Hier haben wir außerdem noch das Bezeichnungsfeld für die Ja/Nein-Felder mit einem Leerzeichen gefüllt, damit die Kontrollkästchen weniger Platz beanspruchen und dabei die Spaltenüberschrift nicht beschnitten wird.
Bild 11: Unterdatenblatt ohne die störenden leeren Datensätze