Es gibt einige Darstellungen, die sich mit Access-Bordmitteln nicht oder nur mit sehr hohem Aufwand realisieren lassen. Dazu gehören beispielsweise alle Konstellationen aus 1:n-Beziehungen mit Unterformularen, bei denen man gern mehr als einen Datensatz im Hauptformular anzeigen würde. Zum Glück erlaubt Access einen Blick über den Tellerrand, und mit dem Webbrowser-Steuerelement und HTML erreichen Sie wohl alle denkbaren Darstellungen – in diesem Fall die Endlosanzeige von 1:n-Beziehungen.
Im vorliegenden Fall sollen alle Abteilungen einer Firma samt den dazugehörigen Mitarbeitern dargestellt werden, und zwar inklusive eines Kontrollkästchens je Abteilung und Mitarbeiter, mit dem man komplette Abteilungen oder einzelne Mitarbeiter aus- und abwählen kann. Das Beispielformular aus Bild 1 gehört zu der Lösung aus dem Beitrag Fehlzeiten verwalten (www.access-im-unternehmen.de/850).

Bild 1: 1:n-Beziehung im Webbrowser-Steuerelement
Das Formular soll die Daten der beiden Tabellen tblAbteilungen und tblMitarbeiter anzeigen, die per 1:n-Beziehung über das Fremdschlüsselfeld AbteilungID der Tabelle tblMitarbeiter miteinander verknüpft sind (s. Bild 3 aussieht. Das Webbrowser-Steuerelement erhält den Namen ctlWebbrowser.

Bild 2: Tabellen der Beispielanwendung

Bild 3: Das Beispielformular in der Entwurfsansicht
Um ein HTML-Dokument mit den Methoden der MSHTML-Bibliothek zu bestücken, benötigen Sie zunächst einen Verweis auf diese Bibliothek. Diesen legen Sie im Verweise-Dialog (Menüeintrag Optionen|Verweise im VBA-Editor) fest (s. Bild 4). Danach können Sie bereits loslegen. Die Prozedur, die durch das Ereignis Beim Laden des Formulars ausgelöst wird, ruft wiederum die Prozedur MitarbeiterAnzeigen auf:

Bild 4: Verweis auf die MSHTML-Bibliothek
Private Sub Form_Load()
MitarbeiterAnzeigen
End Sub
Der weitere Aufbau wird von der Prozedur MitarbeiterAnzeigen gesteuert (s. Listing 1). Die Prozedur legt zunächst mit der Funktion DokumentAnlegen (s. Listing 2) ein Dokument im Webbrowser-Steuerelement an und speichert einen Verweis darauf in der Variablen objDocument.
Listing 1: Mitarbeiter im Webbrowser-Steuerelement anzeigen
Private Sub MitarbeiterAnzeigen()
Dim db As DAO.Database
Dim rstAbteilungen As DAO.Recordset
Dim rstMitarbeiter As DAO.Recordset
Dim objDocument As MSHTML.HTMLDocument
Dim objTable As MSHTML.HTMLTable
Dim objInnerRow As MSHTML.HTMLTableRow
Dim objInnerCell As MSHTML.HTMLTableCell
Dim objCheckbox As MSHTML.HTMLInputElement
Set colCheckboxes_Mitarbeiter = New Collection
Set colCheckboxes_Abteilungen = New Collection
Set objDocument = DokumentHolen
Set objTable = objDocument.createElement("Table")
objDocument.Body.appendChild objTable
objDocument.Body.Style.fontFamily = "calibri"
objDocument.Body.Style.FontSize = "8px"
objTable.Style.borderCollapse = "collapse"
Set db = CurrentDb
Set rstAbteilungen = db.OpenRecordset("SELECT * FROM qryAbteilungenMitMitarbeitern", dbOpenDynaset)
Do While Not rstAbteilungen.EOF
Set objInnerRow = ZeileZelleTabelleAnlegen(objDocument, objTable)
Set objInnerCell = objInnerRow.insertCell
objInnerCell.appendChild CheckboxAbteilungErstellen(objDocument, rstAbteilungen!AbteilungID)
Set objInnerCell = objInnerRow.insertCell
objInnerCell.innerText = rstAbteilungen!Abteilung
Set rstMitarbeiter = db.OpenRecordset("SELECT * FROM qryMitarbeiterauswahl " _
& "WHERE AbteilungID " & rstAbteilungen!AbteilungID, dbOpenDynaset)
Do While Not rstMitarbeiter.EOF
Set objInnerRow = ZeileZelleTabelleAnlegen(objDocument, objTable)
Set objInnerCell = objInnerRow.insertCell
objInnerCell.Width = "30px"
Set objInnerCell = objInnerRow.insertCell
Set objCheckbox = CheckboxMitarbeiterErstellen(objDocument, _
rstMitarbeiter!MitarbeiterID)
objInnerCell.appendChild objCheckbox
objCheckbox.Checked = Not IsNull(rstMitarbeiter!MitarbeiterAnzeigenID)
Set objInnerCell = objInnerRow.insertCell
With objInnerCell
.innerText = rstMitarbeiter!Bezeichnung
.Style.fontFamily = "calibri"
.Style.FontSize = "12px"
End With
rstMitarbeiter.MoveNext
Loop
rstAbteilungen.MoveNext
Loop
Set db = Nothing
End Sub
Listing 2: Browser mit leerem Dokument füllen
Private Function DokumentHolen() As MSHTML.HTMLDocument
Dim objWebbrowser As SHDocVw.WebBrowser
Dim objDocument As MSHTML.HTMLDocument
Set objWebbrowser = GetWebbrowser
DoEvents
objWebbrowser.Navigate "about:blank"
Do
DoEvents
Loop Until objWebbrowser.ReadyState = READYSTATE_COMPLETE
Set objDocument = objWebbrowser.Document
Set DokumentHolen = objDocument
End Function
Außerdem erstellt die Prozedur zwei Collection-Objekte, welche später Verweise auf Wrapper-Klassen für die Checkbox-Steuerelemente zum Auswählen der Abteilungen und der Mitarbeiter aufnehmen – dazu später mehr. Wichtig ist erstmal, dass die Collection-Elemente wie folgt im Kopf des Klassenmoduls des Formulars deklariert werden:
Dim colCheckboxes_Mitarbeiter As Collection Dim colCheckboxes_Abteilungen As Collection
Auch die Wrapper-Klassen werden im Kopf des Moduls deklariert:
Dim objCheckboxWrapper_Mitarbeiter As clsCheckboxWrapper_Mitarbeiter Dim objCheckboxWrapper_Abteilung As clsCheckboxWrapper_Abteilung
Nun geht erstmal der Aufbau der Tabellenstruktur im HTML-Dokument weiter. Die Prozedur erstellt ein HTMLTable-Objekt und hängt es als Kind-Element an das HTMLDocument-Element an. Einige Einstellungen bezüglich der Schriftart sorgen später für ein einheitliches Bild.
Danach kommt auch schon die Datenbank mit ihren Tabellen tblAbteilungen und tblMitarbeiter ins Spiel. Genau genommen öffnet die Prozedur zunächst eine Datensatzgruppe auf Basis der Abfrage qryAbteilungenMitMitarbeitern (s. Bild 5). Diese liefert alle Datensätze der Tabelle tblAbteilungen, denen mindestens ein Mitarbeiter angehört. Diese Abteilungen werden in einer Do While-Schleife durchlaufen. Dabei erstellt die Prozedur MitarbeiterAnzeigen zunächst innerhalb einer Funktion namens ZeileZelleTabelleAnlegen einige Elemente im HTMLTable-Objekt, und zwar zunächst ein HTMLRow-Element, darin ein HTMLCell-Element, darin ein HTMLTable-Element und schließlich noch ein HTMLRow-Element (s. Listing 3).
Listing 3: Unabhängige Zeilen anlegen
Public Function ZeileZelleTabelleAnlegen(objDocument As MSHTML.HTMLDocument, _
objTable As MSHTML.HTMLTable) As MSHTML.HTMLTableRow
Dim objRow As MSHTML.HTMLTableRow
Dim objCell As MSHTML.HTMLTableCell
Dim objInnerTable As MSHTML.HTMLTable
Dim objInnerRow As MSHTML.HTMLTableRow
Set objRow = objTable.insertRow
objRow.Style.verticalAlign = "top"
Set objCell = objRow.insertCell
Set objInnerTable = objDocument.createElement("Table")
objInnerTable.Style.borderCollapse = "collapse"
objCell.appendChild objInnerTable
Set objInnerRow = objInnerTable.insertRow
Set ZeileZelleTabelleAnlegen = objInnerRow
End Function

Bild 5: Datenherkunft für die äußere Schleife
Wozu das Ganze – würde denn nicht eine einfache Zeile reichen Eigentlich ja, wenn wir alle Zellen-Elemente später genau untereinander anordnen wollten. Die Mitarbeiter-Elemente sollen jedoch etwas eingerückt sein, weshalb wir in einer in einer Zelle eingebetteten Tabelle eine weitere Zeile anlegen. Und da wir später das Gleiche für die Mitarbeiter-Zeilen erledigen, können wir darin nach Lust und Laune Tabellenzellen unterbringen, ohne dass deren Positionen vom Raster anderer Zeilen abhängen.
Checkbox für Abteilung einfügen
In diese neue Zeile, die mit objInnerRow referenziert wird, fügt die Prozedur nun zwei Zellen ein: eine für die Checkbox und eine für die Bezeichnung der Abteilung. Die erste Zelle wird durch die Funktion CheckboxAbteilungErstellen gefüllt (s. Listing 4). Diese Prozedur erwartet das HTMLDocument-Element und den Wert des Feldes AbteilungID der Abteilung als Parameter. Damit ausgestattet legt sie zunächst ein neues Checkbox-Element an. Danach folgt direkt die Erstellung einer Instanz der Klasse clsCheckboxWrapper_Abteilung, welche die Funktionen enthält, die beim Anklicken der Checkbox ausgelöst werden. Die Eigenschaft Checkbox der Wrapper-Klasse wird mit einem Verweis auf das Checkbox-Steuerelement gefüllt. Außerdem erhält die Eigenschaft AbteilungID den entsprechenden Wert der aktuell durchlaufenen Abteilung. Schließlich fügt die Prozedur der Eigenschaft Mitarbeiter einen Verweis auf die Collection colCheckboxes_Mitarbeiter hinzu. Dieser wird später benötigt, um beim Aktivieren oder Deaktivieren der kompletten Abteilung alle enthaltenen Mitarbeiter aus- oder abzuwählen.
Listing 4: Hinzufügen einer Checkbox zum Aktivieren einer Abteilung
Public Function CheckboxAbteilungErstellen(objDocument As MSHTML.HTMLDocument, _
lngAbteilungID As Long) As MSHTML.HTMLInputElement
Dim objCheckbox As MSHTML.HTMLInputElement
Set objCheckbox = objDocument.createElement("input")
objCheckbox.Type = "Checkbox"
Set objCheckboxWrapper_Abteilung = New clsCheckboxWrapper_Abteilung
With objCheckboxWrapper_Abteilung
Set .Checkbox = objCheckbox
.AbteilungID = lngAbteilungID
Set .Mitarbeiter = colCheckboxes_Mitarbeiter
End With
colCheckboxes_Abteilungen.Add objCheckboxWrapper_Abteilung, "a" & lngAbteilungID
Set CheckboxAbteilungErstellen = objCheckbox
End Function
Schließlich wird die Wrapper-Klasse der Collection zum Aufbewahren der Abteilungs-Wrapper-Klassen hinzugefügt, damit diese auch nach dem Beenden dieser Prozedur noch existiert.
Mitarbeiter-Checkboxen hinzufügen
Zurück zur Prozedur MitarbeiterAnzeigen. Diese legt nach der Checkbox für die Abteilungen auch noch eine weitere Zelle an, die den Namen der jeweiligen Abteilung aufnimmt. Danach folgen die Mitarbeiter: Ein weiteres Recordset namens rstMitarbeiter wird mit allen Datensätzen der Abfrage qryMitarbeiterauswahl gefüllt, deren AbteilungID mit der aktuellen AbteilungID der äußeren Do While-Schleife übereinstimmt (s. Bild 7). Hier tritt erstmals die Tabelle tblMitarbeiterAusgewaehlt in Aktion: Diese enthält zwei Felder, nämlich ein Primärschlüsselfeld namens MitarbeiterAusgewaehltID und ein Feld zur Aufnahme der MitarbeiterID aller aktuell ausgewählten Mitarbeiter. Wird ein Mitarbeiter im Formular per Checkbox ausgewählt, wird seine MitarbeiterID zu einem neuen Datensatz der Tabelle tblMitarbeiterAusgewaehlt hinzugefügt, wird er abgewählt, wird der Datensatz mit seiner MitarbeiterID gelöscht. Somit kann die Auswahl erfolgen, ohne dass dazu ein zusätzliches Feld in der Tabelle tblMitarbeiter angelegt werden muss.
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
