Home > Artikel > Ausgabe 5/2014 > Mehrere Formularinstanzen anzeigen

Mehrere Formularinstanzen anzeigen

Achtung: Sie sind nicht angemeldet. Wenn Sie Abonnent sind und sich anmelden, lesen Sie den kompletten Artikel, laden das PDF herunter oder probieren die Beispieldatenbank aus (sofern vorhanden).

Die Datensätze einer Tabelle zeigen Sie meist in einer Übersicht wie einem Datenblatt oder einem Listenfeld an. Für die Bearbeitung öffnen Sie den gewünschten Datensatz in einem Detailformular, das die Felder der Tabelle übersichtlich anzeigt. Was aber, wenn Sie einmal mehr als einen Datensatz in der Detailansicht betrachten oder bearbeiten möchten? In diesem Fall hilft die Lösung aus dem vorliegenden Artikel weiter. Wir zeigen Ihnen, wie Sie mehrere Instanzen des gleichen Formulars mit verschiedenen Datensätzen öffnen.

Beispieldatenbank

Die Beispiele dieses Artikels finden Sie in der Datenbank 1405_MehrereFormularinstanzen.mdb.

Hintergrund

Es kann verschiedene Gründe geben, einmal mehr als einen Datensatz im Detail anzuzeigen. Vielleicht möchten Sie beispielsweise einfach einmal die Daten zweier oder mehrerer Datensätze vergleichen oder diese sogar aneinander anpassen, indem Sie die Feldinhalte von einem Formular zum anderen kopieren.

Vermeintlich einfache Lösung

Der einfachste Weg, mehrere Datensätze gleichzeitig anzuzeigen, ist die Erstellung einiger entsprechender Formulare. Diese erhalten dann unterschiedliche Namen wie etwa frmArtikel_1, frmArtikel_2, frmArtikel_3 et cetera. Dies hat aber gleich mehrere Nachteil: Erstens müssen Sie beim Öffnen der Formulare aufpassen, welches schon geöffnet ist, welches der Benutzer vielleicht wieder geschlossen hat und vor allen, welcher Datensatz in welchem Formular angezeigt wird. Der zweite Nachteil ist, dass mehrere gleiche Objekte immer auch einen höheren Wartungsaufwand mit sich bringen: Sollten Sie also etwa vier gleiche Formulare verwenden, müssen Sie eine Änderung entweder immer gleich an allen vier Formularen durchführen oder die mit einem Formular erledigen und die übrigen Formulare löschen und durch die neue Version ersetzen. Der dritte Nachteil ist, dass Sie immer nur eine begrenzte Anzahl von Formularen verwenden können. Gut, dieser Nachteil fällt nicht allzusehr ins Gewicht, denn ab einer bestimmten Anzahl verliert man ja auch den Überblick. Das Fazit lautet jedenfalls: Wir suchen eine bessere Lösung.

Bessere Lösung

Unser Ansatz sieht so aus, dass wir nur ein Detailformular erstellen und dieses zur Anzeige verschiedener Datensätze mehrfach öffnen. Darin steckt, wie Sie sich vorstellen können, etwas mehr Hirnschmalz und außerdem gehören dazu einige Spezialkenntnisse, die Ihnen der vorliegende Artikel vermitteln wird.

Wir erstellen zunächst ein Übersichtsformular frmArtikelUebersicht, dass die Datensätze in einem Unterformular in der Datenblattansicht anzeigt. Der Benutzer soll nun einen der Datensätze markieren und diesen durch einen Klick auf eine Schaltfläche in einem Detailformular öffnen können.

Das Unterformular, dass die Datensätze der Tabelle tblArtikel in der Datenblattansicht anzeigen soll, heißt sfmArtikeluebersicht und sieht wie in Bild 1 aus. Stellen Sie die Tabelle tblArtikel als Datenherkunft des Formulars ein und ziehen Sie alle Felder aus der Feldliste in den Formularentwurf. Legen Sie außerdem für die Eigenschaft Standardansicht den Wert Datenblatt fest.

Unterformular mit Artikeln

Bild 1: Unterformular mit Artikeln

Nun erstellen Sie das Hauptformular frmArtikeluebersicht und ziehen das Unterformular, nachdem Sie es gespeichert und geschlossen haben, aus dem Navigationsbereich in die Entwurfsansicht des Hauptformulars. Fügen Sie dem Hauptformular außerdem eine Schaltfläche namens cmdArtikelAnzeigen mit der Beschriftung Artikel anzeigen hinzu. Das Hauptformular sieht dann wie in Bild 2 aus.

Haupt- und Unterformular zur Auswahl der Detailansichten

Bild 2: Haupt- und Unterformular zur Auswahl der Detailansichten

Detailformular erstellen

Nun benötigen wir noch das Detailformular namens frmArtikeldetails, von dem wir später mehrere Instanzen anzeigen möchten. Dieses füllen Sie ebenfalls mit der Tabelle tblArtikel als Datenherkunft. Ziehen Sie auch hier alle Felder der Datenherkunft in den Detailbereich der Entwurfsansicht. Allerdings dürfen Sie hier ein etwas ordentlicher bei der Anordnung sein, denn die Felder sollen ja nicht in der Datenblattansicht erscheinen, sondern so, wie diese auch im Entwurf aussehen – also wie in Bild 3.

Entwurf des Detailformulars

Bild 3: Entwurf des Detailformulars

Dort haben wir den Artikelnamen nochmals an oberster Stelle im Formularkopf untergebracht, damit der Benutzer direkt sieht, um welchen Artikel es sich handelt. Stellen Sie die Eigenschaften Navigationsschaltflächen, Bildlaufleisten und Datensatzmarkierer jeweils auf den Wert Nein ein, damit das Formular wie in Bild 4 aussieht.

Das Detailformular in der Formularansicht

Bild 4: Das Detailformular in der Formularansicht

Herkömmlicher Aufruf

Die Schaltfläche cmdArtikelAnzeigen füllen wir nun zunächst mit der üblicherweise verwendeten Methode zum Anzeigen eines Formulars mit einem speziellen Datensatz. Dazu wählen Sie im Eigenschaftsfenster des Formulars frmArtikel­uebersicht in der Entwurfsansicht den Wert [Ereignisprozedur] aus und klicken dann auf die Schaltfläche rechts neben der Eigenschaft.

Dies öffnet den VBA-Editor mit einem neuen Klassenmodul für das Formular frmArtikeluebersicht. Dort finden Sie direkt die gewünschte Prozedur cmdArtikelAnzeigen_Click vor, die Sie nun wie in Listing 1 mit Code füllen.

Private Sub cmdArtikelAnzeigen_Click()

     Dim lngArtikelID As Long

     lngArtikelID = Nz(Me!sfmArtikeluebersicht.Form!ArtikelID)

     If Not lngArtikelID = 0 Then

         DoCmd.OpenForm "frmArtikeldetails", WhereCondition:="ArtikelID = " & lngArtikelID

     Else

         MsgBox "Wählen Sie zunächst einen Artikel aus der Liste aus."

     End If

End Sub

Listing 1: Öffnen des Formulars frmArtikeldetails

Die Prozedur deklariert eine Variable namens lngArtikelID, welche den Primärschlüsselwert des aktuell im Unterformular markierten Artikels aufnehmen soll. Die folgende Anweisung ermittelt diesen Wert mit dem Ausdruck Nz(Me!sfmArtikeluebersicht.Form!ArtikelID). Der Ausdruck in der Klammer arbeitet sich über das aktuelle Formular (Me) über das Unterformular-Steuerelement (sfmArtikeluebersicht) zu dem enthaltenen Formular (Form) bis zu dem Feld ArtikelID des aktuellen Datensatzes durch.

Dabei dürfen Sie nicht das Unterformular-Steuerelement und das Unterformular selbst verwechseln, auch wenn beide den gleichen Namen tragen – das Unterformular selbst referenzieren Sie erst mit der Eigenschaft Form des Unterformular-Steuerelements.

Wenn das Unterformular leer ist oder der Benutzer den Datensatzzeiger gerade auf dem leeren, neuen Datensatz platziert hat, liefert dies den Wert Null zurück. In diesem Fall sorgt die Funktion Nz, welche den obigen Ausdruck umschließt, dafür, dass in diesem Fall die Zahl 0 in der Variablen lngArtikelID landet.

Sollte lngArtikelID danach einen Wert ungleich 0 enthalten, ruft die Prozedur im ersten Teil einer entsprechend formulierten If...Then-Bedingung die Methode OpenForm des DoCmd-Objekts auf, die zwei Parameter verwendet: Mit "frmArtikeldetails" den Namen des zu öffnenden Formulars und mit WhereCondition:="ArtikelID = " & lngArtikelID die Bedingung für die Datenherkunft des zu öffnenden Formulars. Letztere lautet nach dem Zusammensetzen etwa so:

ArtikelID = 12

Sollte sich der Datensatzzeiger im Unterformular gerade nicht auf einem Datensatz befinden, erhält lngArtikel­ID den Wert 0. Dies führt zum Else-Teil der If...Then-Bedingung, in dem die Prozedur lediglich eine Meldung ausgibt, dass aktuell kein Datensatz markiert ist.

Das Ergebnis sehen Sie in Bild 5: Die Prozedur öffnet das Formular frmArtikeldetails und zeigt den aktuell im Unterformular markierten Datensatz an.

Öffnen eines Detailformulars für den aktuell markierten Artikel

Bild 5: Öffnen eines Detailformulars für den aktuell markierten Artikel

Probieren wir nun aus, was geschieht, wenn wir ein zweites Mal auf die Schaltfläche cmdArtikelAnzeigen klicken. Das Formular frmArtikeldetails flackert kurz, dann zeigt es den aktuell im Unterformular ausgewählten Datensatz an. Wir können also immer wieder einen anderen Datensatz anzeigen, ohne das Detailformular zu schließen, aber nicht mehrere Artikel gleichzeitig.

Mehrere Formulare, erster Versuch

Um mehrerer Detailformulare zu öffnen, gehen wir einen anderen Weg. Dazu bedarf es zunächst einiger Erläuterungen. Genau wie beispielsweise das Recordset-Objekt ist auch ein Formular nichts anderes als ein Objekt, basierend auf einer Klasse. Sie können mehrere Recordset-Objekte erzeugen, und dies gelingt auch mit Formularen – allerdings nicht mit der oben verwendeten Methode DoCmd.OpenForm.

Während wir damit eine Instanz des Formulars öffnen, die ohne weiteres Zutun existiert, müssen wir beim expliziten Erzeugen eines Formular-Objekts erst eine Objektvariable anlegen, die einen Verweis auf das Formular speichert – anderenfalls würde das Formular gleich wieder im Nirvana verschwinden.

Diese Variable deklarieren wir sinnvollerweise direkt im Kopf des Klassenmoduls Form_frmArtikeluebersicht, damit diese nicht gleich beim Beenden der Prozedur, die das Formular erzeugt und die Variable füllt, gelöscht wird – und damit auch das Formular.

Nun wissen wir aber noch gar nicht, welchen Datentyp ein solches Formular hat. Die allgemeine Klasse Form, mit der Sie Formulare auch referenzieren können, hilft uns an dieser Stelle nicht weiter.

Der Grund ist: Wir möchten ja ein neues Objekt auf Basis dieser Klasse erstellen. VBA wüsste aber beim allgemeinen Typ Form nicht, welches Formular überhaupt gemeint ist.

Die Lösung ist die Verwendung des Namens des Klassenmoduls als Datentyp, also beispielsweise Form_frmArtikeldetails. Dieses Element finden Sie im VBA-Editor ganz einfach mithilfe von IntelliSense (siehe Bild 6).

Datentypen für Formularklassen

Bild 6: Datentypen für Formularklassen

Die Deklarationszeile im Kopf des Klassenmoduls des aufrufenden Formulars frmArtikeluebersicht sieht also so aus:

Dim frm As Form_frmArtikeldetails

Nun fügen wir dem Übersichtsformular eine weitere Schaltfläche namens cmdArtikelAnzeigenII hinzu und füllen diese wie in Listing 2. Die Prozedur erzeugt eine neue Instanz der Klasse Form_frmArtikeldetails und speichert diese in der Variablen frm. Außerdem stellt sie die Eigenschaft Visible auf den Wert True ein, da das Formular sonst gar nicht sichtbar wäre.

Private Sub cmdMehrereArtikelAnzeigen_Click()

     Set frm = New Form_frmArtikeldetails

     frm.Visible = True

End Sub

Listing 2: Erzeugen eines Objekts auf Basis der Klasse Form_frmArtikeldetails

Allein der erste Test enttäuscht: Wir erzeugen durch mehrfaches Anklicken der Schaltfläche Artikel anzeigen II nach wie vor immer nur ein einziges Formular und zweitens zeigt dieses immer den gleichen Datensatz an – nämlich den ersten Datensatz der Datenherkunft.

Also erweitern wir die Prozedur etwas – und zwar wie Listing 3. Dort fügen wir zunächst die Ermittlung des anzuzeigenden Datensatzes ein. Nach dem Einblenden des Formulars stellen wir dessen Eigenschaft Filter auf den gleichen Audruck ein, den wir üblicherweise dem Where­Condition-Parameter der DoCmd.OpenForm-Methode übergeben. Hier ist allerdings zusätzlich nötig, den Filter durch Setzen der Eigenschaft FilterOn auf den Wert True zu aktivieren. Dies gelingt schon besser: Das Formular frmArtikeldetails erscheint nun mit dem gewünschten Datensatz. Allerdings wirkt sich mehrfaches Auswählen und Anzeigen eines Artikels über die Schaltfläche immer noch wie zuvor aus – das Formular wird mit dem neuen Datensatz gefüllt, aber es erscheint kein weiteres Formular.

Private Sub cmdArtikelAnzeigenII_Click()

     Dim lngArtikelID As Long

     lngArtikelID = Nz(Me!sfmArtikeluebersicht.Form!ArtikelID)

     If Not lngArtikelID = 0 Then

         Set frm = New Form_frmArtikeldetails

         With frm

             .Visible = True

             .Filter = "ArtikelID = " & lngArtikelID

             .FilterOn = True

         End With

     Else

         MsgBox "Wählen Sie zunächst einen Artikel aus der Liste aus."

     End If

End Sub

Listing 3: Neues Formular mit dem richtigen Artikel anzeigen

Die Erklärung ist einfach: Das in frm gespeicherte Formular wird beim erneuten Instanzieren und Zuweisen immer wieder überschrieben. Sprich: Solange wir nur eine einzige Variable zum Speichern der Formulare verwenden, können wir auch nur ein einziges Formular gleichzeitig erzeugen.

Weitere Formularinstanz öffnen

Probieren wir also nun etwas aus. Wir deklarieren im Kopf des Klassenmoduls Form_frmArtikeluebersicht eine Variable für ein weiteres Formular:

Dim frmII As Form_frmArtikeldetails

Außerdem fügen wir dem Formular eine weitere Schaltfläche namens cmdNochEinenArtikelAnzeigen hinzu, für die wir im Prinzip die gleiche Ereignisprozedur hinterlegen wie für die vorherige Schaltfläche – mit dem Unterschied, dass wir hier die Variable frmII mit dem neu erzeugten Formular füllen:

...

Set frmII = New Form_frmArtikeldetails

With frmII

.Visible = True

.Filter = "ArtikelID = " & lngArtikelID

.FilterOn = True

End With

...

Wählen Sie nun nacheinander zwei Artikel aus der Liste aus und öffnen diese mit den Schaltflächen cmdArtikelAnzeigenII und cmdNochEinenArtikelAnzeigen, erhalten Sie das Ergebnis aus Bild 7.

Öffnen mehrerer Detailformulare für den aktuell markierten Artikel

Bild 7: Öffnen mehrerer Detailformulare für den aktuell markierten Artikel

Dies kann allerdings nur ein Zwischenergebenis sein, denn Sie wollen ja nicht nur die Details für zwei Artikel anzeigen, sondern vielleicht noch für weitere Artikel. Jedenfalls möchten wir uns nicht durch die Anzahl der dafür deklarierten Variablen einschränken lassen – und schon gar nicht wollen wir verschiedene Schaltflächen verwenden, um mehrere Formularinstanzen zu öffnen.

Objektvariablen ablegen

Praktischerweise finden Sie in der vorliegenden Ausgabe von Access [basics] auch noch den Beitrag Programmieren mit Collections, der die Grundlagen für die folgenden Schritte liefert.

Das Collection-Objekt kann ein oder mehrere Elemente aufnehmen, also Zahlen, Texte, aber auch Verweise auf Objekte wie unsere Formularobjekte. Wenn wir nun nur eine Objektvariable etwa namens frm mit dem Datentyp Form_frmArtikeldetails deklarieren und diese nach dem Füllen mit der ersten Formularinstanz neu erstellen und mit einer weiteren Instanz füllen, überschreiben wir den Verweis auf die erste Formularinstanz wieder.

Wenn wir die erste Objektvariable allerdings als Element einer Collection speichern, können wir die Variable danach mit einer neuen Formularinstanz füllen, ohne die vorherige zu überschreiben.

Wir schauen uns dies Schritt für Schritt an. Als Erstes benötigen wir eine Variable für das Collection-Objekt, die wir wie folgt im Kopf des Klassenmoduls Form_frmArtikeluebersicht anlegen:

Dim colFormulare as Collection

Sie haben das Ende des frei verfügbaren Teil dieses Artikels erreicht!

Wenn Sie mehr lesen und auf viele weitere Artikel zugreifen möchten, melden Sie sich als Abonnent unter Login an. Falls nicht, bestellen Sie doch einfach ein Jahresabonnement!