Flexible HTML-Tabellen mit fester Kopfzeile

Lies diesen Artikel und viele weitere mit einem kostenlosen, einwöchigen Testzugang.

Im Beitrag “HTML-Tabellen mit fester Kopfzeile” haben wir gezeigt, wie Sie Daten aus einer bestimmten Abfrage in einem Webbrowser-Steuerelement so anzeigen, dass die Spaltenköpfe oben fixiert bleiben, während der Benutzer den Inhalt der Tabelle, also die eigentlichen Datensätze, nach unten scrollt. Wir wollen das Beispiel aus diesem Beitrag nun so erweitern, dass Sie die scrollbare HTML-Tabelle für beliebige Tabellen oder Abfragen als Datenquelle nutzen können. Diese sollen per Parameter beim Öffnen des Formulars festgelegt werden. Das Layout der Tabellen sowie die anzuzeigenden Daten sollen dann automatisch ermittelt werden – samt den enthaltenen Feldnamen oder –bezeichnungen als Spaltenköpfen.

Das Ziel dieses Beitrags ist, die Lösung aus dem Artikel HTML-Tabellen mit fester Kopfzeile (www.access-im-unternehmen.de/1188) so anzupassen, dass Sie damit Daten aus beliebigen Tabellen oder Abfragen in einer -scrollbaren HTML-Tabelle anzeigen können.

Das Ergebnis soll dann etwa so aussehen, dass Sie wie in Bild 1 einfach die anzuzeigende Tabelle oder Abfrage aus einem Kombinationsfeld auswählen können, und das Webbrowser-Steuerelement eine Tabelle mit den Daten der gewählten Tabelle oder Abfrage anzeigt.

HTML-Tabelle mit Scrollbalken

Bild 1: HTML-Tabelle mit Scrollbalken

Auswahl der Datenquelle

Dazu benötigen wir zunächst einmal ein Kombinationsfeld, mit dem Sie die Datenquelle auswählen können.

Dieses fügen wir dem Kopf des Formulars wie in Bild 2 hinzu und stellen die Eigenschaft Name auf cboDatenquelle ein.

Hinzufügen des Kombinationsfeldes zur Auswahl der Datenquelle

Bild 2: Hinzufügen des Kombinationsfeldes zur Auswahl der Datenquelle

Als Datensatzherkunft des Kombinationsfeldes verwenden wir die folgende Abfrage:

SELECT Name FROM MSysObjects WHERE Type In (1,5) And Not Left(Name,1)=''~'' And Not Left(Name,4)=''MSys'' And Not Left(Name,2)=''f_'' ORDER BY Name;

Diese Abfrage ermittelt alle Tabellen und Abfragen aus der Systemtabelle MSysObjects und sortiert diese nach dem Namen. Das Kombinationsfeld zeigt die Einträge dann etwa wie in Bild 3 an.

Auswahl der Datenquelle für die HTML-Tabelle

Bild 3: Auswahl der Datenquelle für die HTML-Tabelle

Daten beim Öffnen des Formulars anzeigen

Beim Öffnen des Formulars soll das Webbrowser-Steuerelement direkt die Daten der ersten Datenquelle des Kombinationsfeldes anzeigen.

Dazu sorgen wir dafür, dass direkt der erste Eintrag im Kombinationsfeld vorausgewählt wird, und zwar durch die zweite Zeile der Ereignisprozedur Form_Open:

Private Sub Form_Open(Cancel As Integer)
     Set objWebbrowser = Me!ctlWebbrowser.Object
     Me!cboDatenquelle = Me!cboDatenquelle.ItemData(0)
     Me.TimerInterval = 50
End Sub

Durch Einstellen der Eigenschaft TimerInterval auf den Wert 50 wird 50 Millisekunden nach dem Öffnen des Formulars die folgende Form_Timer-Prozedur ausgelöst:

Private Sub Form_Timer()
     objWebbrowser.Navigate "about:blank"
     Set objDocument = objWebbrowser.Document
     Me.TimerInterval = 0
     DoEvents
     objDocument.body.innerHTML = HTMLCode(Me!cboDatenquelle)
     Inzwischenablage objDocument.body.innerHTML
End Sub

Diese unterscheidet sich in einem Detail von der entsprechenden Prozedur, die wir im oben genannten Beitrag vorgestellt haben. Sie übergibt beim Aufruf der Funktion HTMLCode, welche den HTML-Code für die Darstellung der Tabelle zusammensetzt, für den Parameter strDatenquelle den Namen der Datenquelle.

Das Gleiche geschieht auch in der Prozedur, die der Benutzer durch einen Mausklick auf die Schaltfläche cmdAktualisieren auslöst. Die Ereignisprozedur ruft ebenfalls die Funktion HTMLCode mit dem Wert des Kombinationsfeldes cboDatenquelle als Parameter auf. Diese Prozedur wird dazu wie folgt geändert:

Private Sub cmdAktualisieren_Click()
     objDocument.body.innerHTML = HTMLCode(Me!cboDatenquelle)
     Inzwischenablage objDocument.body.innerHTML
End Sub

Schließlich möchten wir auch, dass der Inhalt des Web-browser-Steuerelements auch beim Aktualisieren der ausgewählten Datenquelle über das Kombinationsfeld cboDatenquelle aktualisiert wird, was wir mit der folgenden Ereignisprozedur realisieren:

Private Sub cboDatenquelle_AfterUpdate()
     If Not Len(Me!cboDatenquelle) = 0 Then
         objDocument.body.innerHTML =  HTMLCode(Me!cboDatenquelle)
     End If
End Sub

HTML-Code datenquellenabhängig zusammenstellen

Damit kommen wir zum interessanten Teil, nämlich dem Code, mit dem wir den HTML-Code abhängig von der gewählten Datenquelle zusammenstellen. Den ersten Teil dieser Funktion finden Sie in Listing 1.

Private Function HTMLCode(strDatenquelle As String) As String
     Dim db As DAO.Database, rst As DAO.Recordset, fld As DAO.Field
     Dim strHTML As String, strFeldname As String
     Dim i As Integer
     Set db = CurrentDb
     Set rst = db.OpenRecordset("SELECT TOP 100 * FROM " & strDatenquelle, dbOpenDynaset)
     strHTML = strHTML & HTMLStyle(rst)
     strHTML = strHTML & "<table class=""tableheaders"">" & vbCrLf
     strHTML = strHTML & "  <thead>" & vbCrLf
     strHTML = strHTML & "    <tr>" & vbCrLf
     For Each fld In rst.Fields
         Select Case fld.Type
             Case dbInteger, dbLong, dbText, dbMemo, dbCurrency, dbDate, dbSingle, dbDouble, dbBoolean
                 strFeldname = ""
                 On Error Resume Next
                 strFeldname = fld.Properties("Caption")
                 On Error GoTo 0
                 If Len(strFeldname) = 0 Then
                     strFeldname = fld.Name
                 End If
                 i = i + 1
                 strHTML = strHTML & "      <th class=""th" & i & """ scope=""col"">" & strFeldname & "</th> " & vbCrLf
             Case Else
         End Select
     Next fld
     strHTML = strHTML & "    </tr>" & vbCrLf
     strHTML = strHTML & "  </thead>" & vbCrLf
     ...
End Function

Listing 1: Listing zum Zusammenstellen des HTML-Codes, Teil 1

Die Funktion erwartet den Namen der mit dem Kombinationsfeld ausgewählten Tabelle oder Abfrage als Parameter. Sie erstellt ein Database-Objekt namens db sowie ein Recordset-Objekt namens rst, welches die ersten 100 Datensätze der gewählten Datenquelle auswählt. Die Erstellung des HTML-Codes dauert für größere Datenmengen relativ lange, daher haben wir diese Beschränkung für die Beispieldatei eingefügt. Sie können TOP 100 in der folgenden Anweisung entfernen, wenn Sie immer alle Datensätze laden wollen:

     Set rst = db.OpenRecordset("SELECT TOP 100 * FROM "  & strDatenquelle, dbOpenDynaset)

Danach ruft die Funktion eine weitere Funktion namens HTMLStyle auf und übergibt dieser das Recordset als Parameter. Die Beschreibung dieser Funktion, die den CSS-Code in Abhängigkeit der Datenquelle zusammenstellt, finden Sie weiter unten.

Danach fügt die Funktion die ersten HTML-Elemente für den Kopfbereich der Tabelle beziehungsweise die umfassende Tabelle an. Nach dem Anlegen der ersten drei Elemente table, thead und tr folgenden die Spaltenüberschriften für die Felder der Datenquelle.

Um dabei auf die jeweiligen Felder der gewählten Datenquelle zuzugreifen, durchlaufen wir die Felder des Recordset-Objekts rst in einer For Each-Schleife und weisen das jeweilige Field-Objekt der Variablen fld zu. Innerhalb dieser Schleife prüfen wir in einer Select Case-Bedingung den Typ des jeweiligen Feldes. Wir wollen nicht alle Felddatentypen in der Tabelle aufführen – so schließen wir beispielsweise OLE- und Anlagefelder aus. Die erste Case-Bedingung behandelt somit die Datentypen Integer, Long, Text, Memo, Currency, Date, Single, Double und Boolean. Weitere Datentypen können Sie nach Bedarf hinzufügen. Sollten Sie die Funktion in einer eigenen Anwendung einsetzen und die dort gewählte Datenquelle enthält ein Feld mit einem Datentyp, der hier nicht behandelt wird, gibt die Prozedur die Nummer des Datentyps im Direktbereich des VBA-Editors aus – dies geschieht im Else-Zweig der Select Case-Bedingung.

Handelt es sich bei fld um ein Feld mit einem unterstützten Datentyp, ermittelt die Funktion entweder den Feldnamen des Feldes oder, falls vorhanden, den Wert der Eigenschaft Beschriftung, den Sie in den Feldeigenschaften im Tabellenentwurf einstellen können.

Wir stellen die Variable strFeldname, die den Feldnamen aufnimmt, zunächst auf eine leere Zeichenkette ein. Dann schalten wir die Fehlerbehandlung temporär aus, und zwar für den Versuch, den Wert der Eigenschaft Caption über die Properties-Auflistung des Feldes zu ermitteln.

Gelingt dies, enthält strFeldname danach die Beschriftung dieses Feldes. Dies prüfen wir in der folgenden If…Then-Bedingung. Hat strFeldname dort eine Länge ungleich 0, tragen wir den Feldnamen aus der Eigenschaft Name in die Variable strFeldname ein und verwenden diesen als Spaltenüberschrift. Nun erhöhen wir eine Zählervariable namens i um den Wert 1 und stellen die HTML-Zeile für die aktuelle Spaltenüberschrift zusammen. Diese sieht dann etwa wie folgt aus:

      <th class="th1" scope="col">ArtikelID</th> 

Danach durchlaufen wir die übrigen Felder des Recordsets und stellen so die Spaltenüberschriften zusammen. Es folgen die schließenden Elemente wie </tr> und </thead>, bevor sich der folgende Teil um die Darstellung der Daten in der HTML-Tabelle kümmert.

Daten in die HTML-Tabelle schreiben

Damit kommen wir zum zweiten Teil der Prozedur, den Sie in Listing 2 finden.

Private Function HTMLCode(strDatenquelle As String) As String
     ...
     strHTML = strHTML & "  <tbody>" & vbCrLf
     strHTML = strHTML & "    <tr>" & vbCrLf
     strHTML = strHTML & "      <td colspan=""" & rst.Fields.Count & """>" & vbCrLf
     strHTML = strHTML & "        <div class=""scrolling"">" & vbCrLf
     strHTML = strHTML & "          <table class=""tablecontent"">" & vbCrLf
     strHTML = strHTML & "            <tbody>" & vbCrLf
     Do While Not rst.EOF
         If rst.AbsolutePosition Mod 2 = 0 Then
             strHTML = strHTML & "              <tr>" & vbCrLf
         Else
             strHTML = strHTML & "              <tr class=""dk"">" & vbCrLf
         End If
         i = 0
         For Each fld In rst.Fields
             i = i + 1
             Select Case fld.Type
                 Case dbInteger, dbLong, dbText, dbMemo, dbDate
                     strHTML = strHTML & "                <td class=""td" & i & """>" & fld.Value & "</td>" _
                         & vbCrLf
                 Case dbCurrency
                     strHTML = strHTML & "                <td class=""td" & i & """>" & Format(fld.Value, "0.00 €") _
                         & "</td>" & vbCrLf
                 Case dbSingle, dbDouble
                     strHTML = strHTML & "                <td class=""td" & i & """>" & Format(fld.Value, "0.00") _
                         & "</td>" & vbCrLf
                 Case dbBoolean
                     strHTML = strHTML & "                <td class=""td" & i & """>" & IIf(fld.Value = -1, _
                         "Ja", "Nein") & "</td>" & vbCrLf
                 Case Else
                     Debug.Print fld.Type
             End Select
         Next fld
         strHTML = strHTML & "              </tr>" & vbCrLf
         rst.MoveNext
     Loop
     strHTML = strHTML & "            </tbody>" & vbCrLf
     strHTML = strHTML & "          </table>" & vbCrLf
     strHTML = strHTML & "        </div>" & vbCrLf
     strHTML = strHTML & "      </td>" & vbCrLf
     strHTML = strHTML & "    </tr>" & vbCrLf
     strHTML = strHTML & "  </tbody>" & vbCrLf
     strHTML = strHTML & "</table>" & vbCrLf
     HTMLCode = strHTML
End Function

Listing 2: Listing zum Zusammenstellen des HTML-Codes, Teil 2

Hier legen wir zunächst die umgebenden Elemente wie <tbody>, <tr> und <td> zusammen, wobei wir den Wert für das Attribut colspan aus der Anzahl der Felder aus der Variablen i ermitteln, welche für jedes berücksichtigte Feld um den Wert 1 erhöht wurde und nicht die Anzahl der tatsächlichen Felder wiedergibt, sondern die Anzahl der Felder mit geeignetem Datentyp. Dies ist wichtig, weil wir in dieser Zelle die untergeordnete Tabelle einfügen, deren Inhalte wir scrollen wollen. Dementsprechend weisen wir in der folgenden Anweisung auch die Klasse scrolling zu. Nun folgen die einleitenden Elemente der Tabelle, nämlich <table> mit der Klasse tablecontent und <tbody>.

Und damit starten wir in die Schleife über alle Datensätze des Recordsets mit der Datenquelle der Tabelle. Hier ermitteln wir mit einer If…Then-Bedingung zunächst, ob es sich um eine ungerade oder gerade Position handelt und stellen dementsprechend für das nun hinzugefügte tr-Element die Klasse dk ein oder auch nicht – diese Klasse wird später per CSS mit einer alternierenden Hintergrundfarbe versehen.

Schließlich durchlaufen wir die Felder des Recordsets für den aktuellen Datensatzes in einer For Each-Schleife mit der Laufvariablen fld, die das jeweilige Feld referenziert. Wir erhöhen dabei zunächst den Wert der Variablen i um den Wert 1. Dann prüfen wir wieder, welchen Felddatentyp das Feld aufweist.

Hier unterscheiden wir etwas feiner als weiter oben, wo wir nur nach den zu berücksichtigenden Felddatentypen und den nicht zu berücksichtigenden Felddatentypen unterschieden haben. Im ersten Case-Teil der Select Case-Bedingung fügen wir die Werte für die Datentypen Integer, Long, Text, Memo und Datum hinzu. Daraus entsteht dann beispielsweise eine Zeile wie die folgende:

<td class="td2">Getränke</td>

Die Zahl 2 in der Bezeichnung der Klasse td2 stammt dabei aus der Variablen i, der für jedes Feld der Wert 1 hinzugefügt wird.

Bei Feldern des Typs Währung fügen wir mit der Format-Funktion noch eine Formatierung hinzu, bei der wie die Anzahl der Nachkommastellen auf 2 einstellen und außerdem das Währungszeichen hinzufügen:

<td class="td6">7,50 €</td>

Für Zahlenfelder der Typen Single oder Double stellen wir ebenfalls per Format-Anweisung die Anzahl der Nachkommastellen auf 2 ein (Format(fld.Value, “0.00”)).

Ende des frei verfügbaren Teil. Wenn Du mehr lesen möchtest, hole Dir ...

Testzugang

eine Woche kostenlosen Zugriff auf diesen und mehr als 1.000 weitere Artikel

diesen und alle anderen Artikel mit dem Jahresabo

Schreibe einen Kommentar