Modale Dialoge mal anders

Unter modalen Dialogen verstehen wir Formulare zur Eingabe von Daten, die so geöffnet werden, dass der Benutzer während der Eingabe nichts anderes in Access erledigen kann als in diesem Formular zu arbeiten. Zum Öffnen eines solchen Formulars verwendet man üblicherweise den Parameter WindowMode:=acDialog, was den praktischen Nebeneffekt hat, dass der aufrufende Code stehen bleibt. Wir zeigen, welche Vor- und Nachteile dies bringt und welche Alternative es gibt.

Der übliche Ablauf beim Einsatz modaler Dialoge, etwa zum Anlegen eines neuen Datensatzes, ist dieser:

Sie öffnen das Formular mit einer Anweisung wie folgt:

DoCmd.OpenForm "Formularname", WindowMode:=acDialog, DataMode:=acFormAdd, OpenArgs:=lngId

Dabei sorgt WindowMode:=acDialog für das Öffnen als modaler Dialog. DataMode:=acFormAdd teilt dem Formular mit, dass es nur einen neuen, leeren Datensatz anzeigen soll, und mit OpenArgs übergeben Sie optional eine Information wie etwa den Fremdschlüsselwert für die Verknüpfung des neuen Datensatzes mit der übergeordneten Tabelle.

Das Popup-Formular öffnet sich, der Benutzer kann nichts anderes tun, als die Daten einzugeben (alle anderen Access-Elemente sind in dieser Zeit tabu), und dann schließt der Benutzer das Formular auf eine von zwei Arten. Die erste offeriert in der Regel eine OK-Schaltfläche, die das Formular mit der folgenden Anweisung unsichtbar schaltet:

Me.Visible = False

Die zweite schließt das Formular gleich komplett:

DoCmd.Close acForm, Me.Name

Beide sorgen dafür, dass das Formular verschwindet und dass der aufrufende Code weiterläuft, da das Formular den Fokus abgegeben hat. Wo aber ist der Unterschied Er liegt darin, dass der aufrufende Code noch auf das unsichtbare Formular zugreifen kann, um den Inhalt seiner Steuerelemente einzulesen – in den meisten Fällen holt es sich dabei die ID des neu angelegten Datensatzes. Dazu muss die Routine prüfen, ob das Formular noch geöffnet ist, was dann als sicheres Indiz dafür gilt, dass es über die OK-Schaltfläche “geschlossen” wurde:

If IstFormularGeoeffnet("Formularname") Then
    €šLese wichtige Felder aus
End If

Welche Nachteile hat dies Im Wesentlichen die folgenden zwei:

Die Datenübergabe an das aufgerufene Formular ist je nach Anzahl der zu übergebenden Informationen aufwendig, weil prinzipiell nur der OpenArgs-Parameter dafür bereitsteht. Und dem kann man mehrere Parameter gleichzeitig auch nur dann unterjubeln, wenn man diese mit einem geeigneten Trennzeichen oder einem anderen speziellen Format auszeichnet und im aufgerufenen Formular entsprechend parst.

Gleichzeitig müssen Sie eine Abhängigkeit vom Popup-Formular zum aufrufenden Formular eingehen. Wenn der Benutzer das Popup-Formular mit der OK-Schaltfläche schließt, wird dieses ja nur unsichtbar geschaltet. Das aufrufende Formular muss es dann nach dem Auslesen der Daten noch schließen. Das ist nicht gut, denn: Wenn die aufrufende Instanz dies nicht weiß, bleibt das Popup-Formular geöffnet. Das wiederum führt dazu, dass beim nächsten Öffnen per DoCmd.OpenForm verwendete Parameter wirkungslos verpuffen.

Alles neu

Schauen wir uns also die alternative Variante an. Diese soll Folgendes ermöglichen:

  • Übergabe beliebig vieler Parameter
  • Problemloses Auslesen der Steuerelemente des Popup-Formulars vor dem Schließen
  • Tatsächliches Schließen des Formulars nach Klick auf die OK-Schaltfläche

Wie funktioniert das Der erste Schritt ist, dass wir das Formular nicht auf dem üblichen Wege als modalen Dialog öffnen. Alternativ instanzieren wir dieses als Objekt auf Basis des Klassenmoduls des Formulars. Falls Sie so etwas noch nie gemacht haben: Keine Angst, die folgenden Abschnitte vermitteln keine Raketentechnik. Voraussetzung hierfür ist, dass das Popup-Formular ein Klassenmodul besitzt. Das können wir aber voraussetzen, wenn dieses mindestens über Schaltflächen mit angehängtem VBA-Code zum Schließen des Formulars verfügt.

Beispielsweise …

Für diesen Beitrag halten die Tabellen der Südsturm-Datenbank her (eine angepasste Variante der Nordwind-Datenbank), und hier im Speziellen tblKategorien und tblArtikel. Das Formular frmKategorienArtikel aus Bild 1 verwaltet die Kategorien und die jeweils darin enthaltenen Daten. Eine Schaltfläche namens cmdNeuerArtikel soll das Popup-Formular frmNeuerArtikel öffnen (siehe Bild 2).

pic001.png

Bild 1: Dieses Formular ruft ein Popup-Formular auf alternative Weise auf.

pic002.png

Bild 2: Popup-Formular zum Anlegen neuer Artikel

Damit wir einen praktischen Anwendungsfall für das Übergeben von Parametern und das Auslesen von Steuerelementen haben, soll das Popup-Formular das Feld Kategorie mit einer Voreinstellung belegen. Diese entspricht der Kategorie, die im Formular frmKategorienArtikel zum Zeitpunkt des Klicks auf cmdNeuerArtikel eingestellt ist.

Außerdem soll das Formular frmKategorienArtikel vor dem Schließen des Popup-Formulars frmNeuerArtikel die ID des neuen Artikels einlesen und den Datensatzzeiger des Unterformulars sfmKategorienArtikel darauf einstellen.

Für den nächsten Schritt muss das Popup-Formular ein Klassenmodul enthalten. Dazu legen wir einfach schon einmal die folgenden beiden Ereignisprozeduren für die Schaltflächen cmdOK und cmdAbbrechen an. Beide schließen das Formular, die Schaltfläche cmdAbbrechen macht zuvor noch die änderungen rückgängig:

Private Sub cmdOK_Click()
    DoCmd.Close acForm, Me.Name
    End Sub
Private Sub cmdAbbrechen_Click()
    Me.Undo
    DoCmd.Close acForm, Me.Name
    End Sub

Beim Aufruf des Popup-Formulars sind nun ein paar Schritte mehr erforderlich als beim puren DoCmd.OpenForm. Der erste ist, dass Sie eine Objektvariable für das Klassenmodul des Popup-Formulars im Kopf des Moduls des aufrufenden Formulars anlegen:

Dim objFrmNeuerArtikel As Form_frmNeuerArtikel

Beim Klicken auf die Schaltfläche cmdNeuerArtikel wird dann diese Routine ausgelöst:

Private Sub cmdNeuerArtikel_Click()
    Set objFrmNeuerArtikel =
    New Form_frmNeuerArtikel
    With objFrmNeuerArtikel
    .DefaultEditing = 1
    .Modal = True
    .Visible = True
    End With
    End Sub

Die Routine erzeugt zunächst eine neue Instanz des Klassenmoduls Form_frmNeuerArtikel, was zusammen mit dem Sichtbarmachen einem herkömmlichen DoCmd.OpenForm-Aufruf entspricht. Hinzu kommt das Einstellen der verborgenen Eigenschaft DefaultEditing auf den Wert 1 und der Eigenschaft Modal auf True. Letzteres bewirkt zusammen mit dem Setzen der Eigenschaft Popup des Formulars die Anzeige des Formulars als modaler Dialog. Hier gibt es einen wichtigen Unterschied im Vergleich zu der Wirkung von DoCmd.OpenForm “frm”, WindowMode:=acDialog: Der Benutzer kann zwar genauso wenig auf die übrigen Access-Elemente zugreifen, während das Formular geöffnet ist, aber der aufrufende Code läuft weiter. Und genau das eröffnet ganz neue Möglichkeiten – dazu jedoch später mehr.

Zunächst noch einige Anmerkungen: Wenn Sie ein Formular entsprechend mit dem Parameter DataMode der DoCmd.OpenForm-Methode öffnen möchten, müssen Sie die entsprechenden VBA-Eigenschaften dafür verwenden.

Genau genommen reicht es, wenn Sie wie in obigem Aufruf einfach nur die Eigenschaft DefaultEditing auf einen Wert zwischen 1 und 4 einstellen. Tabelle 1 zeigt, welche Werte die verschiedenen Eigenschaften eines Formulars bei Aufrufen mit unterschiedlichen Werten für den Parameter DataMode annehmen. Wenn Sie einen neuen Datensatz anlegen möchten, brauchen Sie DefaultEditing also einfach nur auf den Wert 1 einzustellen. Übrigens können Sie DefaultEditing auch mit dem Wert 4 belegen. Dies führt dann dazu, dass der Benutzer alles mit den Daten im Formular erledigen kann, außer neue Daten hinzufügen.

DefaultEditing ist übrigens eine veraltete und im Objektkatalog verborgene Eigenschaft, die wohl offiziell nicht mehr unterstützt wird. Stattdessen soll man nun die übrigen Eigenschaften aus Tab. 1 verwenden, um die datenbezogenen Eigenschaften eines Formulars einzustellen. In der Tat zieht das Einstellen von DefaultEditing die entsprechende Anpassung der übrigen Eigenschaften nach sich, wie der Aufruf der folgenden Testroutine belegt:

Public Sub test()
Dim i As Integer
With Forms!frmNeuerArtikel
For i = 1 To 5
 .DefaultEditing = i
    Debug.Print "DefaultEditing: " _
    & .DefaultEditing
    Debug.Print "DataEntry: " _
    & .DataEntry
    Debug.Print "AllowEditions: " _
    & .AllowAdditions
    Debug.Print "AllowDeletions: " _
    & .AllowDeletions
    Debug.Print "AllowEdits: " _
    & .AllowEdits
    Debug.Print "AllowEditing: " _
    & .AllowEditing
    Debug.Print "AllowUpdating: " _
    & .AllowUpdating
Next i
End With
End Sub

Das Durchlaufen der Schleife bis zum Wert 5 belegt dann auch, dass es nur vier mögliche Werte gibt – siehe Fehlermeldung aus Bild 3. Diese liefert auch noch die deutschen Bezeichnungen für die vier Einstellungen.

pic003.png

Bild 3: Ausgabe der durch das ändern der Eigenschaft DefaultEditing angepassten Attribute

Werte übergeben

Nach diesem kleinen Ausflug kehren wir zurück zum Beispiel. Das Popup-Formular dient dem Hinzufügen neuer Artikel für die Kategorie, die im aufrufenden Formular gerade angezeigt wurde. Daher macht es Sinn, das Feld KategorieID vorzubelegen. Beim klassischen Aufruf mit DoCmd.OpenForm würden Sie diesen Wert mit dem Öffnungsparameter OpenArgs an das Formular übergeben und diesen dort mit Me.OpenArgs auswerten.

Im vorliegenden Fall gehen wir einen völlig anderen Weg, der aber auch erst dadurch möglich wird, dass wir das Formular zwar als modalen Dialog aufrufen, der aufrufende Code aber weiterläuft. Wir könnten also schlicht auf das aufgerufene Formular zugreifen und den Wert seiner Steuerelemente ändern. Dies ginge etwa so:

Forms!frmNeuerArtikel!KategorieID = 1

Damit würden Sie aber schon einen konkreten Wert einstellen und den neuen, leeren Datensatz in den Dirty-Zustand versetzen. Dies würde sich zunächst wie in Bild 4 bemerkbar machen, außerdem könnte der Benutzer das Formular nun nicht mehr einfach mit der OK-Schaltfläche schließen, weil quasi ein neuer Datensatz angelegt wurde, der validiert wird. Dies führt in der Beispieldatenbank etwa dazu, dass Access nach der Eingabe eines Artikelnamens verlangt.

pic004.png

Bild 4: Das Einstellen eines Feldes auf einen neuen Wert versetzt das Formular in den Dirty-Status.

Besser wäre es, die ID der Kategorie vorerst als Standardwert für die Kategorie einzustellen:

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

den kompletten Artikel im PDF-Format mit Beispieldatenbank

diesen und alle anderen Artikel mit dem Jahresabo

Schreibe einen Kommentar