Mehrere Datensätze pro Spalte in Formularen

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

üblicherweise landen in einem Access-Formular entweder die Details eines Datensatzes oder mehrere Datensätze. Erstere können über das Formular verteilt werden, Letztere erscheinen untereinander in der Datenblattansicht oder der Endlosansicht. Mit einigen Unterformular-Steuerelementen lassen sich jedoch auch mehrere Datensätze nebeneinander anzeigen. Dieser Beitrag zeigt die Grundlagen zur Anzeige mehrerer Datensätze in einer Matrix von Unterformularen.

Grundlage für die Anzeige mehrerer Datensätze nebeneinander ist, dass Sie für jeden Datensatz ein Unterformular anlegen und diese dann nebeneinander anordnen. Die Datenherkünfte der Unterformulare müssen Sie dann noch so gestalten, dass diese jeweils den gewünschten Datensatz anzeigen. Wenn Sie also beispielsweise drei Kundendatensätze nebeneinander anzeigen wollen, müssten Sie dem ersten Unterformular den ersten Datensatz der Datenherkunft , dem zweiten den zweiten Datensatz und so weiter zuweisen.

Das Blättern in solchen Daten ist natürlich nicht mehr über die Bildlaufleiste möglich – dazu müssten Sie sich mit eigenen Steuerelementen wie etwa einer Nach oben– oder Nach unten-Schaltfläche behelfen. Natürlich könnte man auch die herkömmliche Bildlaufleiste nutzen, aber dann müsste das Formular so viele Unterformulare enthalten, dass alle Datensätze der Datenherkunft angezeigt werden können.

Mit steigender Datensatzanzahl sinkt hier die Performance, und auch die Anzahl der Unterformularsteuerelemente ist natürlich begrenzt. Also wollen wir es lieber bei einer vordefinierten Anzahl belassen und eigene Schaltflächen zum Blättern zwischen den Datensätzen verwenden. Das Ergebnis soll in der Rohfassung wie in Bild 1 aussehen. Das Hauptformular legen Sie als einfaches Formular mit der Bezeichnung frmKundenNebeneinander an und speichern dieses.

Unterformulare in mehreren Spalten zur Anzeige von Daten

Bild 1: Unterformulare in mehreren Spalten zur Anzeige von Daten

Unterformulare hinzufügen

Im folgenden Beispiel wollen wir zwölf Unterformulare in drei Spalten und vier Zeilen anordnen. Die Unterformulare sollen die Bezeichnungen sfm01, smf02 und so weiter erhalten. Damit die Unterformulare korrekt positioniert und mit den richtigen Abmessungen ausgestattet werden, wollen wir diese mit einem kleinen Skript zum Hauptformular hinzufügen.

Dieses sieht wie in Listing 1 aus und ist in der Beispieldatenbank im Modul mdlTools zu finden. Die Prozedur erwartet einige Parameter, welche den Namen des mit Unterformularen auszustattenden Formulars sowie die Abmessungen für die Unterformularsteuerelemente enthalten. Dabei liefern intX und intY zunächst die Anzahl der anzulegenden Unterformulare je Zeile und Spalte. lngBreite und lngHoehe enthalten die Abmessungen, lngAbstand-X und lngAbstandY den Abstand der Unterformulare untereinander und zum linken und oberen Rand des Formulars. Schließlich legen Sie mit strSubform, soweit gewünscht, noch den Wert der Eigenschaft Herkunftsobjekt (VBA: SourceObject) fest.

Public Sub UnterformulareAnlegen(strForm As String, intX As Integer, intY As Integer, lngBreite As Long, _
         lngHoehe As Long, lngAbstandX As Long, lngAbstandY As Long, Optional strSubform As String)
     Dim frm As Form
     Dim ctl As Control
     Dim i As Integer
     Dim x As Integer
     Dim y As Integer
     On Error Resume Next
     DoCmd.Close acForm, strForm
     On Error GoTo 0
     DoCmd.OpenForm strForm, acDesign
     Set frm = Forms(strForm)
     For i = frm.Controls.Count - 1 To 0 Step -1
         Set ctl = frm.Controls(i)
         Select Case ctl.ControlType
             Case acLabel, acSubform
                 DeleteControl frm.Name, ctl.Name
         End Select
     Next i
     i = 0
     For y = 1 To intY
         For x = 1 To intX
             i = i + 1
             Set ctl = CreateControl(frm.Name, acSubform, acDetail, , , lngAbstandX + (lngAbstandX + lngBreite) _
                 * (x - 1), lngAbstandY + (lngAbstandX + lngHoehe) * (y - 1), lngBreite, lngHoehe)
             ctl.Name = "sfm" & Format(i, "00")
             If Len(strSubform) > 0 Then
                 ctl.SourceObject = strSubform
             End If
         Next x
     Next y
End Sub

Listing 1: Hinzufügen der Unterformulare zum Hauptformular

Für die Konstellation in der Beispieldatenbank haben wir den folgenden Aufruf der Prozedur zusammengestellt:

UnterformulareAnlegen "frmKundenNebeneinander", 3, 4, 4000, 3000, 100, 100, "sfmKundenNebeneinander"

Damit legt diese 3 x 4 Unterformularsteuerelemente an und füllt diese gleich mit dem Unterformular sfmKundenNebeneinander. Die Prozedur schließt zunächst das mit strForm übergebene Formular, sofern dieses noch geöffnet ist, und öffnet es erneut, diesmal in der Entwurfsansicht. Dann speichert es einen Verweis auf das Formular in der Variablen frm.

In einer For…Next-Schleife über alle im Formular enthaltenen Steuerelemente löscht sie dann alle bereits vorhandenen Unterformulare. Sie sollten die Routine also nicht für Formulare nutzen, die bereits für andere Zwecke vorgesehene Unterformulare enthalten, oder aber eine Prüfung einbauen, welche nur die in vorherigen Aufrufen angelegte Unterformularsteuerelemente löscht. Zum Löschen der Steuerelemente verwendet die Routine die DeleteControl-Methode, die den Namen des Formulars und des zu löschenden Steuerelements enthält.

Danach durchläuft die Prozedur zwei verschachtelte For…Next-Schleifen über die Werte von 1 bis intY beziehungsweise 1 bis intX. In der Schleife erhöht sie den Wert der Variablen i, die zuvor auf 0 eingestellt wurde, um 1. i soll die Nummer für den Steuerelementnamen (sfm01, sfm02 und so weiter) liefern. Nun folgt die Methode CreateControl, welche das eigentliche Steuerelement erstellt. Sie erwartet den Namen des Zielformulars, den Typ des zu erstellenden Steuerelements, den Zielbereich (hier den Detailbereich) sowie die Koordinaten und Abmessungen.

Die Abmessungen entnimmt die Routine den Parametern intHoehe und intBreite, die Koordinaten werden für jedes Steuerelement neu berechnet. Der Abstand vom linken Formularrand stammt dabei aus der Formel lngAbstandX + (lngAbstandX + lngBreite) * (x – 1). Im ersten Durchlauf ist x = 0, also ist der Abstand der mit lngAbstandX übergebene Wert. Für die folgenden Elemente, die natürlich rechts neben dem jeweils zuvor platzierten Element landen sollen, ermittelt die Routine die Position aus dem Abstand des ersten Elements vom linken Rand plus dem Produkt der Breite eines Elements plus dem einfachen Abstand und dem Index des Steuerelements. Auf die gleiche Art berechnet die Routine den Abstand vom oberen Formularrand.

Die Variable ctl speichert den Verweis auf das soeben erstellte Steuerelement. Damit weist die Routine noch den Namen für das Steuerelement zu. Wenn strSubform den Namen des Unterformulars enthält, der im Unterformularsteuerelement angezeigt werden soll, weist die Prozedur diesen der Eigenschaft SourceObject des Unterformularsteuerelements zu. Diesen Vorgang wiederholt die Prozedur, bis alle Zeilen und Spalten in den For…Next-Schleifen durchlaufen wurden. Das Ergebnis sieht zu diesem Zeitpunkt etwa wie in Bild 2 aus.

Frisch angelegte Unterformulare in der Entwurfsansicht

Bild 2: Frisch angelegte Unterformulare in der Entwurfsansicht

Unterformular anlegen

Schließlich benötigen wir auch noch das Unterformular, das in den Unterformularsteuerelementen des Hauptformulars erscheinen und die verschiedenen Datensätze anzeigen soll. Die Herkunftstabelle heißt tblKunden und liefert einige Felder, die wir wie in Bild 3 im Unterformular sfmKundenNebeneinander anorden. Außerdem legen wir dort schon einmal eine Schaltfläche namens cmdLoeschen an, die später das Löschen des im Unterformular angezeigten Datensatzes erlauben soll.

Das Unterformular der Beispielanwendung

Bild 3: Das Unterformular der Beispielanwendung

Wenn Sie nun das Hauptformular in der Formularansicht öffnen, zeigt dieses für jedes Unterformular den gleichen Datensatz an (s. Bild 4). Kein Wunder: Das Unterformular ist ja in allen Fällen genau gleich aufgebaut und zeigt dementsprechend auch die gleichen Daten an – zumindest, bis wir gleich mit einigen Zeilen Code eingreifen.

Gleicher Datensatz in allen Unterformularen

Bild 4: Gleicher Datensatz in allen Unterformularen

Unterformulare mit verschiedenen Datensätzen füllen

Die Unterformulare füllen wir gleich beim öffnen des Hauptformulars, und zwar in der Ereignisprozedur, die durch das Ereignis Beim Laden ausgelöst wird (s. Listing 2). Diese Prozedur verwendet bereits einige Variablen, die wir modulweit im Kopf des Klassenmoduls Form_frmKundenNebeneinander deklarieren:

Private Sub Form_Load()
     Dim intElemente As Integer
     Dim j As Integer
     Set db = CurrentDb
     Set rst = db.OpenRecordset("SELECT * FROM tblKunden", dbOpenDynaset)
     intStartdatensatz = 1
     UnterformulareFuellen intElemente
     Me!cmdNachUnten.Enabled = Not (intStartdatensatz + intElemente - 1 >= rst.RecordCount)
     Me!cmdNachOben.Enabled = Not intStartdatensatz = 1
End Sub

Listing 2: Füllen der Unterformulare mit den gewünschten Datensätzen

Dim db As DAO.Database
Dim rst As DAO.Recordset
Dim intStartdatensatz As Integer

Die Prozedur füllt die Variable db mit einem Verweis auf das aktuelle Database-Objekt. Die Recordset-Variable rst füllt die Prozedur mit den Daten der Tabelle tblKunden.

Mit der Variablen intElemente als Parameter ruft die Prozedur damit die Routine UnterformulareFuellen auf. Diese ist letztlich dafür verantwortlich, in den Unterformularen den richtigen Datensatz anzuzeigen. Da wir später mit dem Formular durch die Kundendatensätze blättern wollen, benötigen wir noch die aktuelle Position. Dazu tragen wir den Wert 1 in die Variable intStartdatensatz ein, was bedeutet, dass das erste Unterformular den ersten Datensatz der Datenherkunft anzeigt. Schließlich soll das Formular zwei Schaltflächen namens cmdNachOben und cmdNachUnten enthalten, mit denen der Benutzer zu den vorherigen beziehungsweise nächsten Datensätzen blättern kann, sowie eine Schaltfläche zum Anlegen eines neuen Datensatzes (cmdNeu) – s. Bild 5.

Schaltflächen zum Blättern nach oben und unten und zum Anlegen eines neuen Datensatzes

Bild 5: Schaltflächen zum Blättern nach oben und unten und zum Anlegen eines neuen Datensatzes

Wenn das Formular gerade die ersten Datensätze anzeigt, soll die Schaltfläche cmdNachOben natürlich deaktiviert sein, das Gleiche gilt für die Schaltfläche cmdNachUnten auf der letzten Seite. Dies erledigen die letzten beiden Anweisungen der Prozedur. Die Bedingung für das Deaktivieren der Schaltfläche cmdNachUnten lautet Not (intStartdatensatz + intElemente – 1 >= rst.RecordCount). Der Startdatensatz (in diesem Fall 1) plus der Anzahl der angezeigten Datensätze (von der Prozedur UnterformulareFuellen mit dem Parameter intElemente zurückgeliefert) minus 1 soll nicht größer oder gleich der Anzahl der Datensätze der Datenherkunft sein. Die Nach oben-Schaltfläche wird immer aktiviert, wenn der Startdatensatz nicht der erste ist (intStartdatensatz = 1).

Unterformulare füllen

Die Ereignisprozedur Form_Load ruft die Routine UnterformulareFuellen aus Listing 3 auf, um die entsprechenden Datensätze in den einzelnen Unterformularen anzuzeigen. Diese verwendet einen Parameter namens intElemente, der die Anzahl der auf dieser Seite gefüllten Unterformulare zurückgeben soll. Die Prozedur durchläuft eine Do While-Schleife, die erst abgebrochen wird, wenn das Ende des Recordsets erreicht ist, also keine Datensätze mehr in Unterformularen abzubilden sind, oder intElemente kleiner als intUnterformulare wird, also alle Unterformulare gefüllt sind. intElemente wird gleich in der ersten Anweisung um 1 erhöht. Dann ermittelt die Prozedur den Wert des Primärschlüsselfeldes des aktuellen Datensatzes und speichert diesen in der Variablen lngKundeID.

Private Sub UnterformulareFuellen(intElemente As Integer)
     Dim lngKundeID As Long
     Dim intLetzterEintrag As Integer
     Dim j As Integer
     Do While Not rst.EOF And intElemente < intUnterformulare
         intElemente = intElemente + 1
         lngKundeID = rst!KundeID
         With Me("sfm" & Format(intElemente, "00"))
             .Form.RecordSource = "SELECT * FROM tblKunden WHERE KundeID = " & lngKundeID
             .Visible = True
         End With
         rst.MoveNext
     Loop
     If intElemente < intUnterformulare Then
         For j = intElemente + 1 To intUnterformulare
             With Me("sfm" & Format(j, "00"))
                 .Form.RecordSource = ""
                 .Visible = False
             End With
         Next j
     End If
     If rst.EOF = True Then
         intLetzterEintrag = rst.RecordCount
     Else
         intLetzterEintrag = rst.AbsolutePosition
     End If
     Me!lblEintraege.Caption = intStartdatensatz & "-" & intLetzterEintrag & " von " & rst.RecordCount
End Sub

Listing 3: Unterformulare füllen

Damit beginnen die Arbeiten am Unterformular: Dieses erhält zunächst eine Abfrage als Datensatzquelle, die den Kunden mit dem in lngKundeID gespeicherten Primärschlüsselwert liefert. Die Visible-Eigenschaft erhält den Wert True, damit das Unterformularsteuerelement eingeblendet wird. Dies wiederholt die Schleife so lange, bis die Abbruchbedingung erfüllt ist.

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