Home > Artikel > Ausgabe 11/2016 > Mehrere Instanzen eines Formulars

Mehrere Instanzen eines Formulars

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 meisten Anwendungen zeigen, wie Sie aus einer Liste von Datensätzen einen per Doppelklick öffnen und in einem Detailformular anzeigen. Nach dem Bearbeiten schließen Sie diesen und wenden sich dem nächsten Datensatz zu. Was aber, wenn Sie einmal mehrere Datensätze parallel anzeigen möchten, um diese beispielsweise zu vergleichen – oder weil Sie einfach den einen Datensatz später noch einmal weiterbearbeiten möchten. Dieser Artikel zeigt Ihnen, wie Sie dieses Verhalten mit Access-Formularen abbilden können.

Beispieldatenbank

Die Beispiele dieses Artikels finden Sie in der Datenbank 1611_Formularinstanzen.accdb.

Formulare öffnen auf herkömmliche Art

Wenn Sie auf die herkömmliche Art ein Formular öffnen möchten, verwenden Sie dazu beispielsweise den folgenden Befehl:

DoCmd.OpenForm "frmKunde"

Damit erhalten Sie dann eine Instanz des gewünschten Formulars. Mit weiteren Parametern können Sie etwa noch angeben, dass Sie gleich beim Öffnen einen bestimmten Kunden anzeigen wollen:

DoCmd.OpenForm "frmKunde", WhereCondition:="KundeID = 1"

Wenn Sie die gleiche Anweisung jedoch noch ein weiteres Mal ausführen, um damit beispielsweise einen anderen Kunden im gleichen Formular anzuzeigen, gelingt dies nicht wie gewünscht.

Wir schauen uns dies am Beispiel des Formulars frmKunde an, dass im Entwurf wie in Bild 1 aussieht und die Tabelle tblKunden mit einigen Beispieldatensätzen als Datenherkunft verwendet.

Formular-Entwurf unseres Beispielformulars

Bild 1: Formular-Entwurf unseres Beispielformulars

Öffnen wir das Formular mit der obigen DoCmd.OpenForm-Anweisung, die Sie der Einfachheit halber einfach im Direktbereich eingeben (zu öffnen mit Strg + G) und mit der Eingabetaste ausführen, erhalten wir das Formular aus Bild 2. Führen Sie diesen Befehl jedoch direkt danach erneut aus, wobei Sie lediglich den WhereCondition-Parameter wie folgt ändern, wird zwar der zweite Kunde im Formular angezeigt, der erste verschwindet allerdings:

Erster Datensatz im Beispielformular

Bild 2: Erster Datensatz im Beispielformular

DoCmd.OpenForm "frmKunde", WhereCondition:="KundeID = 2"

Das bedeutet, dass wir uns eine alternative Möglichkeit einfallen lassen müssen.

Formular-Instanz öffnen

Zum Glück gibt es noch eine zweite Methode, um ein Formular zu öffnen. Im Grunde ist DoCmd.OpenForm eine vereinfachte Variante, die Sie so etwa in anderen Sprachen wie Visual Basic oder C# nicht finden werden. Dort wird immer eine Objektvariable auf Basis der entsprechenden Klasse, hier eben das betroffene Formular, deklariert und dann initialisiert. Gegebenenfalls ist das initialisierte Objekt dann noch sichtbar zu machen, was bei Access-Formularen der Fall ist. Wie also sieht diese alternative Methode unter Access aus und können wir auch hier den gewünschten Datensatz an das Formular übermitteln?

Dazu wollen wir uns erst einmal ein Standardmodul anlegen, in dem wir eine Prozedur erstellen, um das Verhalten nachzuprogrammieren.

Das Standardmodul heißt mdlFormularinstanzen und wird im Visual Basic Editor (zu öffnen mit Alt + F11) mit dem Menübefehl Einfügen|Modul eingefügt.

Keine Formularinstanz ohne Formularklasse

Ein Schritt ist noch nötig, bevor wir per VBA eine neue Instanz unseres Formulars frmKunde erstellen können. Genau genommen erstellen wir nämlich keine Instanz des Formulars, sondern der Code behind-Klasse, also des Klassenmoduls, dass beispielsweise dann angelegt wird, wenn Sie ein Ereignis des Formulars implementieren oder die Eigenschaft Enthält Modul des Formulars auf Ja einstellen.

Da das Formular eine Schaltfläche mit der Beschriftung OK enthält, welche das Formular nach erfolgter Bearbeitung oder Ansicht der Daten schließen soll, legen wir gleich den Wert [Ereignisprozedur] für die Ereigniseigenschaft Beim Klicken dieses Steuerelements an und klicken auf die Schaltfläche mit den drei Punkten, um die entsprechende Ereignisprozedur anzulegen – und somit auch das benötigte Klassenmodul:

Private Sub cmdOK_Click()

DoCmd.Close acForm, Me.Name

End Sub

Danach wechseln wir wieder zum Modul mdlFormularinstanzen, wo wir eine neue Prozedur namens Formularinstanz hinzufügen und für diese eine Variable namens frm deklarieren. Diese soll den Typ des Klassenmoduls des Formulars frmKunde erhalten, der dann auch prompt per IntelliSense angeboten wird (siehe Bild 3). Also führen wir nun die geplanten Schritte durch, die wie folgt aussehen – deklarieren, initialisieren und sichtbar machen:

Formularklasse per IntelliSense

Bild 3: Formularklasse per IntelliSense

Public Sub Formularinstanz()

Dim frm As Form_frmKunde

Set frm = New Form_frmKunde

frm.Visible = True

End Sub

Der Plan war nicht gut genug: Das Formular erscheint für Bruchteile einer Sekunde und verschwindet dann wieder. Der Grund ist eindeutig: Die Variable frm, mit der wir es referenzieren, ist innerhalb der Prozedur Formularinstanz deklariert.

Das heißt, dass ihre Lebensdauer mit dem Ablauf des Formulars endet. Die Folgerung: Die Variable muss außerhalb der Prozedur deklariert werden. Mit der folgenden Variante klappt es besser – das Formular erscheint wie gewünscht:

Dim frm As Form_frmKunde

Public Sub Formularinstanz()

Set frm = New Form_frmKunde

frm.Visible = True

End Sub

Mit der Schaltfläche cmdOK lässt es sich auch problemlos wieder schließen.

Gewünschten Datensatz anzeigen

Es fehlt allerdings noch die Möglichkeit, gleich beim Anzeigen einen bestimmten Datensatz anzuzeigen. Normalerweise haben wir diesen mit dem Parameter WhereCondition übergeben, der uns hier aber nicht zur Verfügung steht.

Allerdings haben wir ja nun eine Objektvariable, mit der wir auf die Instanz des Formulars verweisen. Warum also nicht gleich auch die Eigenschaften des Formulars nutzen – wie beispielsweise die Filter-Eigenschaft? Erweitern wir also unsere Prozedur und fügen einen Filterausdruck hinzu, der den Kunden mit dem Wert 2 für das Feld KundeID liefert:

Public Sub Formularinstanz()

Set frm = New Form_frmKunde

frm.Visible = True

frm.Filter = "KundeID = 2"

frm.FilterOn = True

End Sub

Das erneute Ausführen der Prozedur zeigt nun den gewünschten Kunden an (siehe Bild 4). Nun ändern wir die Zeile mit dem Filter wie folgt:

Formularinstanz mit Wunschkunde

Bild 4: Formularinstanz mit Wunschkunde

frm.Filter = "KundeID = 3"

Rufen wir die Prozedur nun erneut auf, zeigt das Formular zwar den gewünschten Kunden an, allerdings ist das Formular mit dem vorherigen Kunden nicht mehr vorhanden. Kein Wunder: Wir haben ja nur eine Instanzvariable namens frm, deren Inhalt beim Überschreiben gelöscht wird – und mit ihm das referenzierte Formular.

Mehrere Instanzen öffnen

Wie öffnen wir nun mehrere Instanzen gleichzeitig? Die einfachste Methode: Wir deklarieren einfach für jede Instanz eine eigene Variable. Dies dient zunächst nur Beispielzwecken, um zu veranschaulichen, wie es funktioniert. Jede der beiden Instanzen aus dem folgenden Beispiel wir durch die neue Prozedur Formularinstanzen initialisiert, eingeblendet und mit dem gewünschten Datensatz versehen. Das Ergebnis sieht wie in Bild 5 aus:

Zwei Formularinstanzen

Bild 5: Zwei Formularinstanzen

Dim frm1 As Form_frmKunde

Dim frm2 As Form_frmKunde

Public Sub Formularinstanzen()

Set frm1 = New Form_frmKunde

With frm1

.Visible = True

.Filter = "KundeID = 1"

.FilterOn = True

End With

Set frm2 = New Form_frmKunde

With frm2

.Visible = True

.Filter = "KundeID = 2"

.FilterOn = True

End With

End Sub

Damit haben wir schon einmal gezeigt, wie es gelingen kann. Allerdings ist dies natürlich keine tragfähige Lösung, denn wir wollen ja nicht für jeden zu öffnenden Kunden eine eigene Objektvariable deklarieren und die Prozedur Formularinstanzen entsprechend erweitern – zudem wir ja nicht absehen können, wie viele Kunden der Benutzer anzeigen möchte.

Und es gibt noch ein weiteres Problem: Die beiden Formular werden genau übereinander geöffnet, wodurch der Benutzer gar nicht erkennen kann, dass mehrere Formular existieren.

Viele Objekte verwalten

Wir kümmern uns zunächst darum, mehrere Formularinstanzen zu öffnen, ohne dass wir für jede eine eigene Variable deklarieren müssen. Aber wie erledigen wir das? Voraussetzung ist, dass wir irgendwie eine Referenz auf die Formularinstanz halten, ohne dafür jeweils eine eigene Variable bereitstellen zu müssen. Dafür gibt es eine einfache Möglichkeit: Wir verwenden nur eine Objektevariable, die wir diesmal wieder innerhalb der Prozedur deklarieren und füllen. Diesmal speichern wir diese allerdings vor dem Prozedurende in einer Collection! Diese deklarieren wir wie folgt im Kopf des Standardmoduls:

Public colForms As Collection

Dann verwenden wir die folgende Prozedur, um zwei Formulare mit der gleichen Objektvariable zu initialisieren und in der Collection zu speichern. Diese müssen wir natürlich zuvor mit dem New-Schlüsselwort initialisieren. Dann erstellen wir wie gewohnt die Form_frmKunde-Objekte, blenden das Formular ein und lassen den gewünschten Kunden anzeigen. Der wichtige Schritt ist das Hinzufügen der Objektvariablen zur Collection colForms mit den Add-Befehl:

Public Sub FormularCollection()

Dim frm As Form_frmKunde

Set colForms = New Collection

Set frm = New Form_frmKunde

With frm

.Visible = True

.Filter = "KundeID = 1"

.FilterOn = True

End With

colForms.Add frm

Set frm = New Form_frmKunde

With frm

.Visible = True

.Filter = "KundeID = 2"

.FilterOn = True

End With

colForms.Add frm

End Sub

Das Ergebnis ist das Gleiche wie zuvor – die Prozedur öffnet zwei Formulare und zeigt diese an. Die Collection colForms haben wir mit dem Public-Schlüsselwort deklariert. So können wir nun betrachten, warum die Lösung in dieser Form noch nicht perfekt ist. Schließen Sie dazu einmal die beiden soeben geöffneten Formulare und geben Sie dann den folgenden Befehl im Direktbereich des VBA-Editors ein:

  colForms.Count

2

Wie Sie sehen, enthält die Collection noch zwei Objekte, die allerdings, da die Formulare bereits geschlossen wurden, nicht mehr nützlich sind. Also sollten wir uns auch darum kümmern, die Collection nach dem Anlegen der Formulare auch wieder aufzuräumen, wenn die Formulare geschlossen wurden.

Dazu wollen wir aber zunächst ein kleines Übersichtsformular erstellen, mit dem wir die Formulare komfortabel öffnen und schließen können.

Übersichtsformular

Dieses Formular soll alle Kunden in einem Listenfeld anzeigen und das Öffnen per Doppelklick ermöglichen. Das Formular frmKundeuebersicht enthält neben dem Listenfeld lstKunden noch zwei Schaltflächen namens cmdOK und cmdAlleSchliessen. Die Funktion der ersten Schaltfläche ist klar, die zweite Schaltfläche dient dazu, alle vom Übersichtsformular aus geöffneten Kunden-Formulare zu schließen (siehe Bild 6). Einzelne Formulare soll der Benutzer mit der OK-Schaltfläche der Formulare selbst schließen. Schließlich sollen auch alle Kunden-Formulare automatisch geschlossen werden, wenn der Benutzer das Formular frmKundenuebersicht schließt.

Übersichtsformular in der Entwurfsansicht

Bild 6: Übersichtsformular in der Entwurfsansicht

Das Listenfeld des Formulars erhält die folgende Datensatzherkunft:

SELECT KundeID, Firma & " - " & Nachname & ", " & Vorname FROM tblKunden;

Die Eigenschaft Spaltenanzahl stellen wir auf 2, die Eigenschaft Spaltenbreiten auf 0cm ein. So wird der Primärschlüsselwert ausgeblendet und nur der gewünschte Inhalt angezeigt. In der Formularansicht sieht das Übersichtsformular nun wie in Bild 7 aus.

Übersichtsformular in der Formularansicht

Bild 7: Übersichtsformular in der Formularansicht

Vorüberlegung

Wir wollen mit dem Übersichtsformular ja nicht nur wild Formularinstanzen öffnen, sondern auch dafür sorgen, dass diese kontrolliert geschlossen werden – und vor allem sollen Kunden doppelt in den Formularen angezeigt werden geschweige denn Fehler auftreten, wenn wir einen Kunden anzeigen, schließen und erneut anzeigen.

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!