Mehrere Instanzen eines Formulars

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

Möchten Sie weiterlesen? Dann lösen Sie Ihr Ticket!
Hier geht es zur Bestellung des Jahresabonnements des Magazins Access [basics]:
Zur Bestellung ...
Danach greifen Sie sofort auf alle rund 400 Artikel unseres Angebots zu - auch auf diesen hier!
Oder haben Sie bereits Zugangsdaten? Dann loggen Sie sich gleich hier ein:

Schreibe einen Kommentar