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