UserForm-Objekt/benutzerdefinierte Dialoge  
Autor/Einsender:
Datum:
  Angie
02/2006
Anregungen/Tipps an:   Angie
Das Thema UserForms/benutzerdefinierte Dialoge ist sehr weitläufig. In diesem Tutorial werden die Methoden und Anweisungen für das Laden, Anzeigen, Ausblenden und Entladen eines benutzerdefinierten Dialogs zusammengefasst, als auch die dafür wichtigen UserForm-Ereignisse. Ein wichtiges Thema hier ist der Unterschied zwischen der Verwendung des Schlüsselworts Me und dem Namen der UserForm zum Ansprechen der UserForm und der darauf befindlichen Steuerelemente im Codebereich der UserForm. Als abschließendes Beispiel wird gezeigt, wie ein Dialog aufgerufen und ausgewertet werden kann.
Es wird hier davon ausgegangen, dass zumindest Grundkenntnisse in VBA vorhanden sind, und so auch bekannt ist, wie man eine UserForm zum VBA-Projekt und zum Fenster Steuerelemente hinzufügt. Sowohl in der Word- als auch in der Excel-Hilfe ist unter Erstellen eines benutzerdefinierten Dialogfelds eine ausführliche Anleitung vorhanden.
1.  UserForm-Objekt, UserForms-Auflistung
2.  UserForm-Methoden und Anweisungen
Load-Anweisung
Show-Methode
Hide-Methode
Unload-Anweisung
3.  UserForm-Ereignisse
Initialize-Ereignis
Activate-Ereignis
QueryClose-Ereignis
Terminate-Ereignis
4.  Programmiertechniken allgemein
Steuerelemente ansprechen
Schlüsselwort Me vs. UserForm-Name
Variablendefinition
5.  Dialog aufrufen und auswerten
Schließen der UserForm verhindern
Dialog auswerten
6.  Ausblick
7.  Download der Demos
Bei Fragen zu diesem Tutorial nutzen Sie bitte unser VB-/VBA-Forum.

  UserForm-Objekt, UserForms-Auflistung
Ein UserForm-Objekt ist ein benutzerdefinierter Dialog, das einen Teil einer Benutzeroberfläche einer Anwendung darstellt. Über Dialoge können vom Anwender bequem Eingaben gemacht werden. Am anschaulichsten demonstrieren das die in Excel und Word integrierten Dialoge.
Beim Hinzufügen eines UserForm-Objekts zu einem VBA-Projekt wird automatisch eine Default-Instanz der UserForm erstellt, dabei handelt es sich um ein globales Objekt. Die globale Objekt-Variable, die den selben Namen wie der Name der UserForm hat, steht im gesamten VBA-Projekt zur Verfügung.
Ab Office 2000 ist es möglich, einen Dialog sowohl über die Show-Methode als auch ihrer Eigenschaft ShowModal ungebunden anzuzeigen, was bedeutet, dass gleichzeitig auch ein Dokument aktiv sein kann. Wird ein Dialog gebunden angezeigt, muss der Anwender reagieren, bevor er einen anderen Teil der Anwendung verwenden kann. Es wird kein nachfolgender Code ausgeführt, bis das UserForm-Objekt ausgeblendet oder entladen wird. Auch wenn andere Dialoge in der Anwendung deaktiviert sind, während ein UserForm-Objekt angezeigt wird, sind andere Anwendungen nicht deaktiviert.
Die UserForms-Auflistung ist eine Auflistung, deren Elemente jedes geladene UserForm in einer Anwendung darstellen. Die UserForms-Auflistung besitzt eine Count-Eigenschaft, eine Item-Eigenschaft und eine Add-Methode. Count gibt die Anzahl der in der Anwendung geladenen UserForm-Objekte an, Item (das Standardelement) gibt ein bestimmtes Element einer Auflistung an, und Add legt ein neues UserForm-Element in der Auflistung ab.
Hinweis
In diesem Tutorial wird nur auf gebundene Dialoge eingegangen!

  UserForm-Methoden und Anweisungen [ Top ]
Zum Laden und Entladen einer UserForm stehen die Anweisungen Load und Unload zur Verfügung, zum Anzeigen und Ausblenden die Methoden Show und Hide.
Load-Anweisung
Die Load-Anweisung lädt ein Objekt, zeigt es jedoch nicht an.
 
Load Objekt
 
Wird ein Objekt geladen, wird es im Speicher abgelegt, es ist jedoch nicht sichtbar. Mit der Show-Methode wird das Objekt sichtbar gemacht.
Solange ein Objekt nicht sichtbar ist, kann ein Benutzer mit ihm nicht interagieren, das Objekt kann jedoch über Code beeinflusst werden, z. B. im Initialize-Ereignis, das beim Laden der UserForm automatisch ausgeführt wird. Ist das angegebene Objekt nicht geladen wenn die Show-Methode aufgerufen wird, lädt Visual Basic es automatisch.
Unter bestimmten Umständen, beispielsweise bei komplexen Dialogen, kann es sinnvoll sein, die UserForm zunächst in den Speicher zu laden und erst anschließend anzuzeigen.
Show-Methode
Mit der Show-Methode wird ein UserForm-Objekt angezeigt.
 
Objekt.Show
 
Ab Office 2000 ist es möglich, einen Dialog sowohl über die Show-Methode als auch ihrer Eigenschaft ShowModal ungebunden anzuzeigen.
Hide-Methode
Die Hide-Methode blendet ein Objekt aus, entlädt es aber nicht.
 
Objekt.Hide
 
Wenn ein Objekt ausgeblendet ist, wird es vom Bildschirm entfernt und die zugehörige Visible-Eigenschaft auf False gesetzt. Auf die Steuerelemente eines ausgeblendeten Objekts kann der Anwender nicht zugreifen, sie werden jedoch der ausgeführten Anwendung programmseitig zur Verfügung gestellt, sowie anderen Prozessen, die mit dieser Anwendung über Automatisierung kommunizieren.
Ist ein UserForm-Objekt ausgeblendet, kann der Benutzer mit der Anwendung erst dann wieder interagieren, wenn der Code in der Ereignisprozedur vollständig ausgeführt wurde, durch die das UserForm-Objekt ausgeblendet wurde.
Die Hide-Methode lädt das UserForm-Objekt, auch wenn es noch nicht geladen ist, zeigt es jedoch nicht an.
Unload-Anweisung
Die Unload-Anweisung entfernt ein Objekt aus dem Speicher.
 
Unload Objekt
 
Beim Entladen eines Objekts wird es aus dem Speicher entfernt und jeglicher Speicher, der mit diesem Objekt verbunden ist, freigegeben. Solange das Objekt nicht erneut in den Speicher geladen wird, kann ein Anwender nicht mit dem Objekt interagieren, und das Objekt kann auch nicht mittels Code verändert werden.

  UserForm-Ereignisse [ Top ]
Ein UserForm-Objekt unterstützt viele vordefinierte Ereignisse. Die für das Laden und Entladen einer UserForm relevanten Ereignisse sind Initialize, QueryClose und Terminate, aber auch ggf. das Activate-Ereignis.
Initialize-Ereignis
Das Initialize-Ereignis tritt ein, nachdem ein Objekt geladen, aber bevor es angezeigt wird.
 
Private Sub UserForm_Initialize()
  '...
End Sub
 
Das Initialize-Ereignis wird gewöhnlich dazu verwendet, eine UserForm für die Verwendung vorzubereiten, Variablen können Startwerte zugewiesen und Steuerelemente verschoben oder in ihrer Größe angepasst werden.
Activate-Ereignis
Das Activate-Ereignis tritt ein, wenn ein Objekt zum aktiven Fenster wird.
 
Private Sub UserForm_Activate()
  '...
End Sub
 
Ein Objekt kann aktiviert werden, indem im Code die Show-Methode verwendet wird. Das Activate-Ereignis kann nur dann eintreten, wenn ein Objekt sichtbar ist. Eine mit der Load-Anweisung geladene UserForm ist so lange nicht sichtbar, bis sie mit der Show-Methode angezeigt wird.
QueryClose-Ereignis
Das QueryClose-Ereignis tritt ein, bevor eine UserForm geschlossen wird.
 
Private Sub UserForm_QueryClose(Cancel As Integer, _
        CloseMode As Integer)
  '...
End Sub
 
Mit diesem Ereignis wird normalerweise sichergestellt, dass die in einer Anwendung enthaltenen Dialoge keine nicht beendeten Operationen enthalten, wenn die Anwendung geschlossen wird. Sind beispielsweise neue Daten noch nicht gespeichert, kann die Anwendung den Benutzer auffordern, die Daten zu speichern.
Wird eine Anwendung geschlossen, kann die QueryClose-Ereignisprozedur verwendet werden, um die Cancel-Eigenschaft auf den Wert True festzulegen, wodurch der Schließvorgang gestoppt wird.
Anmerkung: Die Rückgabewerte des Arguments CloseMode können in der VB(A)-Hilfe nachgelesen werden.
Terminate-Ereignis
Das Terminate-Ereignis tritt ein, wenn alle Verweise auf eine Objektinstanz aus dem Speicher entfernt werden, indem alle auf das Objekt verweisende Variablen auf den Wert Nothing gesetzt werden oder wenn sich der letzte Verweis auf das Objekt außerhalb des Gültigkeitsbereichs befindet.
 
Private Sub UserForm_Terminate()
  '...
End Sub
 
Das Terminate-Ereignis tritt ein, nachdem das Objekt entladen wurde, aber nicht wenn die Instanzen der UserForm oder der Klasse aus dem Speicher entfernt werden, weil die Anwendung nicht ordnungsgemäß beendet wurde. Ruft die Anwendung z. B. die End-Anweisung auf, bevor alle vorhandenen Instanzen der Klasse oder der UserForm aus dem Speicher entfernt wurden, wird das Terminate-Ereignis für diese Klasse oder dieser UserForm nicht ausgelöst.

  Programmiertechniken allgemein [ Top ]
Mit den Beispielen in diesem Kapitel wird der Unterschied zwischen der Verwendung des Schlüsselworts Me und dem Namen der UserForm zum Ansprechen der UserForm und der darauf befindlichen Steuerelemente im Codebereich der UserForm aufgezeigt.
Um die folgenden Beispiele nachvollziehen zu können, werden eine UserForm (FrmDialog) mit einer TextBox (txtData1) und zwei CommandButtons (cmdOK und cmdCancel) und ein Modul benötigt.
Anmerkung: Beim Hinzufügen von Steuerelementen werden diesen automatisch Namen zugewiesen, die jedoch nicht sehr aussagekräftig sind. Nachdem die Namen der Steuerelemente in den Ereignisprozeduren und auch im weiteren Code verwendet werden, empfiehlt es sich, die Namen im Eigenschaftsfenster (F4) zu ändern. Auch der Name der UserForm kann und sollte entsprechend geändert werden.
Für die verschiedenen Demos muss der Code wie angegeben im Modul und/oder im Codebereich der UserForm komplett ersetzt werden, oder aber Sie verwenden die Excel-Arbeitsmappe im Download, in der die Beispiele in leicht abgewandelter Form auch enthalten sind.
Steuerelemente im Codebereich der UserForm ansprechen
Im Codebereich einer UserForm kann einer TextBox ein Wert beispielsweise zugewiesen werden mit
 
1:  Me.txtData1.Text = "Mein Text"
2:  FrmDialog.txtData1.Text = "Mein Text"
3:  txtData1.Text = "Mein Text"
 
Die obige Liste könnte noch um einige Variationen ergänzt werden, unter anderem könnte die Eigenschaft Text in allen Fällen weggelassen werden. Die Angabe der Eigenschaft trägt jedoch m. E. zur besseren Lesbarkeit des Codes bei. Die Standardeigenschaft für die TextBox ist die Value-Eigenschaft. Jeder Wert, der der Text-Eigenschaft zugewiesen wird, wird auch der Value-Eigenschaft zugewiesen.
Um in der Entwicklungsumgebung die Vorteile von IntelliSense nutzen zu können, wird gerne entweder das Schlüsselwort Me oder der Name der UserForm verwendet. IntelliSense bezieht sich auf die Funktionalität der Codeansicht und ermöglicht das automatische Vervollständigen von Befehlen und stellt kontextbezogene Listen bereit, die Code- und Skripterstellungselemente, auch die auf einer UserForm befindlichen Steuerelemente, enthalten.
In vielen Foren erhält man auf die Frage, ob man das Schlüsselwort Me, den Namen der UserForm oder nichts verwenden soll, als Antwort, dass es egal wäre, und das Schlüsselwort Me vorzuziehen wäre, wenn man schreibfaul ist. In den weiteren Ausführungen und Beispielen wird jedoch aufgezeigt, dass es einen Unterschied gibt, je nach dem wie eine UserForm aufgerufen wird.
Das Schlüsselwort Me verhält sich wie eine implizit deklarierte Variable. Es steht allen Prozeduren in einem Klassenmodul automatisch zur Verfügung. Wenn eine Klasse mehrere Instanzen haben kann, stellt Me eine Möglichkeit dar, um sich auf diejenige Instanz der Klasse zu beziehen, in der Code ausgeführt wird. Die Verwendung von Me ist insbesondere dann hilfreich, wenn Sie Informationen zur momentan ausgeführten Instanz einer Klasse an eine Prozedur in einem anderen Modul übergeben möchten.
Bei der Verwendung von FrmDialog "verbaut" man sich unter anderem die Möglichkeit, mehrere Instanzen einer UserForm verwenden zu können. Es können zwar mehrere Instanzen erstellt werden, diese sind jedoch mehr oder weniger "nutzlos".
Wer nicht schreibfaul ist, kann wie in obiger Code-Zeile 3 verfahren.
Schlüsselwort Me vs. UserForm-Name
Zum Anzeigen einer UserForm ist die Verwendung der Show-Methode in Verbindung mit der Objektinstanz, die beim Hinzufügen der UserForm zum VBA-Projekt automatisch erstellt wurde, am meisten verbreitet, zum Entladen der UserForm die Unload-Anweisung. Hier wird als Objekt-Bezeichner der Name der UserForm FrmDialog verwendet.
Gegen die folgende Vorgehensweise ist an sich nichts einzuwenden, es hat jedoch zur Folge, dass nur die Default-Instanz der UserForm sinnvoll verwendet werden kann.
Code im Codebereich der UserForm
 
Option Explicit

Private Sub UserForm_Initialize()
1:  MsgBox "UserForm_Initialize-Ereignis"
2:  FrmDialog.Caption = "Demo - " & FrmDialog.Name
3:  FrmDialog.txtData.Text = "Mein Text"
End Sub

Private Sub cmdOK_Click()
4:  MsgBox "Tue etwas mit der Eingabe: " & FrmDialog.txtData.Text
5:  Unload FrmDialog
End Sub

Private Sub cmdCancel_Click()
6:  Unload FrmDialog
End Sub
 
Code im Modul
 
Option Explicit

Sub DemoAufruf_1()
    FrmDialog.Show
End Sub
 
Lässt man den Code im Codebereich der UserForm so wie er ist, also "gespickt" mit FrmDialog, und erstellt dann mit folgendem Aufruf eine neue Instanz der UserForm, so wird die neue Instanz der UserForm objForm zwar angezeigt, aber weder der Titel der UserForm noch der Text für die TextBox werden zugewiesen.
Code im Modul
 
Option Explicit

Sub DemoAufruf_2()
1:  Dim objForm As FrmDialog

  'Neue Instanz der UserForm erstellen
2:  Set objForm = New FrmDialog

  'Anzahl geladene UserForms: 2
3:  MsgBox "Anzahl geladene UserForms: " & UserForms.Count

  'Die mit Set objForm = New FrmDialog
  'neu erstellt Instanz der UserForm anzeigen
4:  objForm.Show  'UserForm gebunden anzeigen!

  'Die Makroausführung wird erst fortgesetzt, wenn die
  'UserForm mit dem Schließen 'X' geschlossen wird!
 
  'Referenziertes Objekt freigeben
5:  Set objForm = Nothing

  'Die mit Set objForm = New FrmDialog wurde vom
  'User geschlossen, Anzahl geladene UserForms: 0 oder 1
6:  MsgBox "Anzahl geladene UserForms: " & UserForms.Count

  'Default-Instanz der UserForm anzeigen
7:  FrmDialog.Show

  'Die Makroausführung wird erst fortgesetzt, wenn die
  'UserForm geschlossen wird!
  'Anzahl geladene UserForms: 0
8:  MsgBox "Anzahl geladene UserForms: " & UserForms.Count
End Sub
 
Bei Ausführung von Zeile 2 in obigem Beispiel tritt automatisch das Initialize-Ereignis der UserForm ein. Im Initialize-Ereignis der UserForm wird jedoch nicht der neu erstellten UserForm-Instanz mit dem Objektverweis objForm der Titel und der Text zugewiesen, sondern explizit mit FrmDialog. der von der Anwendung (Excel, Word usw.) erstellten Default-Instanz der UserForm. Das heißt also, beim Zuweisen des Titels wird die Default-Instanz automatisch in den Speicher geladen, jedoch nicht angezeigt, und somit wird auch das Initialize-Ereignis ein zweites Mal ausgeführt.
Damit ist auch erklärt, warum in Zeile 3 bereits zwei UserForm-Objekte im Speicher geladen sind. Noch sind die beiden Objekte für den Anwender nicht sichtbar. Erst in Zeile 4 wird die mit dem Objektverweis objForm neu erstellte UserForm-Instanz angezeigt, allerdings ohne neuem Titel und auch ohne dem Text in der TextBox. Klickt man nun auf einen der CommandButtons, egal welchen, so wird die Default-Instanz entladen, beim nächsten Klick wieder in den Speicher geladen.
Das heißt, dass mit jedem 2. Klick im Click-Ereignis des CommandButtons 'OK' in der Zeile
 
4:  MsgBox "Tue etwas mit der Eingabe: " & FrmDialog.txtData.Text
 
oder im Click-Ereignis des CommandButtons 'Abbrechen' in der Zeile
 
6:  Unload FrmDialog
 
die Default-Instanz immer wieder in den Speicher geladen wird.
Die einzige Möglichkeit mit dem obigen Beispiel die neu erstellte UserForm-Instanz objForm aus dem Speicher zu entfernen, ist das Schließen-'X' der UserForm.
Nach dem Schließen der UserForm wird die Makroausführung fortgesetzt. In Zeile 7 wird die Default-Instanz angezeigt. Je nachdem, ob beim "Experimentieren" mit den CommandButtons die Default-Instanz entladen wurde oder nicht, wird das Initialize-Ereignis ggf. nochmals ausgeführt, Titel und TextBox sind zugewiesen und die UserForm kann "ordentlich" entladen werden.
Im letzten Beispiel ist also deutlich zu erkennen, welche Auswirkungen es haben kann, wenn man im Codebereich der UserForm den Namen der UserForm als Objekt-Bezeichner verwendet.
Ersetzt man im Codebereich der UserForm FrmDialog mit dem Schlüsselwort Me, wie im nächsten Beispiel, läuft soweit alles wie gewünscht, beiden Instanzen der UserForm wird der Titel und der Text zugewiesen, und auch das Entladen funktioniert tadellos. Es ist immer jeweils nur die "gewünschte" UserForm geladen und auch für den Anwender sichtbar. Der Code im Codebereich des Moduls ist identisch mit dem vorherigen Beispiel, lediglich die Kommentare zum Code sind entsprechend angepasst.
Code im Codebereich der UserForm
 
Option Explicit

Private Sub UserForm_Initialize()
1:  MsgBox "UserForm_Initialize-Ereignis"
2:  Me.Caption = "Demo - " & Me.Name
3:  Me.txtData.Text = "Mein Text"
End Sub

Private Sub cmdOK_Click()
4:  MsgBox "Tue etwas mit der Eingabe: " & Me.txtData.Text
5:  Unload Me
End Sub

Private Sub cmdCancel_Click()
6:  Unload Me
End Sub
 
Code im Modul
 
Option Explicit

Sub DemoAufruf_3()
1:  Dim objForm As FrmDialog

  'Neue Instanz der UserForm erstellen
2:  Set objForm = New FrmDialog

  'Anzahl geladene UserForms: 1
3:  MsgBox "Anzahl geladene UserForms: " & UserForms.Count

  'Die mit Set objForm = New FrmDialog
  'neu erstellt Instanz der UserForm anzeigen
4:  objForm.Show  'UserForm gebunden anzeigen!

  'Die Makroausführung wird erst fortgesetzt, wenn die
  'UserForm geschlossen wird!
 
  'Referenziertes Objekt freigeben
5:  Set objForm = Nothing

  'Die mit Set objForm = New FrmDialog wurde vom
  'User geschlossen, 'Anzahl geladene UserForms: 0
6:  MsgBox "Anzahl geladene UserForms: " & UserForms.Count

  'Default-Instanz der UserForm anzeigen
7:  FrmDialog.Show

  'Die Makroausführung wird erst fortgesetzt, wenn die
  'UserForm geschlossen wird!

  'Anzahl geladene UserForms: 0
8:  MsgBox "Anzahl geladene UserForms: " & UserForms.Count
End Sub
 
Fazit Schlüsselwort Me vs. UserForm-Name
Es ist nicht zu empfehlen, im Codebereich der UserForm auf die von der Anwendung (Excel, Word usw.) erstellte Default-Instanz der UserForm mit FrmDialog zu verweisen. Außer der Nutzung des IntelliSense gibt es keine Vorteile, jedoch folgende Nachteile:
"Unkontrolliertes" Referenzieren der Default-Instanz der UserForm.
Es kann nur eine Instanz der UserForm sinnvoll verwendet werden.
Code ist nicht "pflegeleicht". Wird beispielsweise der Name der UserForm geändert, muss dieser auch im gesamten Code geändert werden.
Anders sieht es bei der Verwendung des Schlüsselworts Me aus. Soweit mir bekannt ist, gibt es keine Nachteile, im Vergleich zu FrmDialog jedoch einige Vorteile:
Es können mehrere Instanzen der UserForm erstellt und verwendet werden.
Me bezieht sich immer auf die Instanz, in der der Code ausgeführt wird, auch wenn es sich um die Default-Instanz handelt.
Kein "unkontrolliertes" Referenzieren der Default-Instanz.
Code ist "pflegeleicht".
Die Nutzung des IntelliSense ist auch mit dem Schlüsselwort Me möglich.
Variablendefinition für das UserForm-Objekt
Wer auf Nummer sicher gehen will, vermeidet die Verwendung der von der Anwendung (Excel, Word usw.) erstellten Default-Instanz der UserForm, in unserem Beispiel die UserForm FrmDialog. In den weiteren Beispielen wird also immer eine neue Instanz der Default-Instanz erstellt.
Die Variable für die neu zu erstellende Instanz der UserForm kann als Typ Object, UserForm oder FrmDialog deklariert werden.
 
1:  Dim objForm As Object
2:  Dim objForm As UserForm

3:  Dim objForm As FrmDialog
4:  Dim objForm As New FrmDialog
 
1: Object Einer Variablen, die als Object deklariert wurde, kann anschließend mit der Set-Anweisung ein Verweis auf jedes beliebige von der Anwendung erzeugte Objekt zugewiesen werden. Das heißt, man kann der Variable ein beliebiges UserForm-Objekt zuweisen, in Excel aber auch ein Blatt (Tabellenblatt oder Diagrammblatt), ein eingebettetes Diagramm-Objekt oder ein Shape usw.

Hier ist keine Nutzung des IntelliSense möglich, da der Anwendung das Objekt, welches zur Laufzeit zugewiesen wird, zur Entwurfszeit nicht bekannt ist.
2: UserForm Einer Variablen, die als UserForm deklariert wurde, kann anschließend mit der Set-Anweisung ein Verweis auf jede beliebige UserForm im Projekt zugewiesen werden.

Bei Nutzung des IntelliSense werden in der Liste zwar UserForm-spezifische Eigenschaften und Methoden angezeigt, jedoch weder die auf der UserForm befindlichen Steuerelemente noch die als Public deklarierten Prozeduren, Funktionen und Ereignisse.
3: FrmDialog Einer Variablen, die in diesem Beispiel als FrmDialog deklariert wurde, kann anschließend mit der Set-Anweisung ein Verweis auf die dem Projekt hinzugefügten UserForm mit dem Namen zugewiesen werden.

Bei Nutzung des IntelliSense werden in der Liste UserForm-spezifische Eigenschaften und Methoden angezeigt, aber auch die auf der UserForm befindlichen Steuerelemente und als Public deklarierten Prozeduren, Funktionen und Ereignisse.
4: New FrmDialog   Wie FrmDialog, mit dem Unterschied, dass das Schlüsselwort New das implizite Erstellen eines Objekts ermöglicht. Wenn Sie New bei der Deklaration der Objektvariablen verwenden, wird eine neue Instanz des Objekts auf Grund des ersten Verweises darauf erstellt, so dass Sie die Set-Anweisung für die Zuweisung des Objektverweises nicht verwenden müssen. Dies hat jedoch den Nachteil, dass ggf. wieder ein "unkontrolliertes" Laden der UserForm ausgelöst wird.
Wird die UserForm zur Entwurfszeit zum VBA-Projekt hinzugefügt, ist auf Grund der in obiger Tabelle beschriebenen Vor- und Nachteile zu empfehlen, die Objekt-Variable wie in Zeile 3 zu definieren.
Der Code im Codebereich der UserForm ist für die nächste Demo soweit noch unverändert.
Code im Codebereich der UserForm
 
Option Explicit

Private Sub UserForm_Initialize()
1:  MsgBox "UserForm_Initialize-Ereignis"
2:  Me.Caption = "Demo - " & Me.Name
3:  Me.txtData.Text = "Mein Text"
End Sub

Private Sub cmdOK_Click()
4:  MsgBox "Tue etwas mit der Eingabe: " & Me.txtData.Text
5:  Unload Me
End Sub

Private Sub cmdCancel_Click()
6:  Unload Me
End Sub
 
Mit dem folgenden Code wird in Zeile 1 zunächst eine lokale Objekt-Variable vom Typ FrmDialog definiert, in Zeile 2 eine neue Instanz der UserForm in den Speicher geladen, und in Zeile 3 mit der Show-Methode gebunden(!) angezeigt. Die Makroausführung wird erst fortgesetzt, wenn die UserForm geschlossen wird. In Zeile 4 wird das referenzierte Objekt freigeben.
Code im Modul
 
Option Explicit

Sub DemoAufruf_4()
1:  Dim objForm As FrmDialog
2:  Set objForm = New FrmDialog
3:  objForm.Show
4:  Set objForm = Nothing
End Sub
 

  Dialog aufrufen und auswerten [ Top ]
In den bisherigen Beispielen wurde die UserForm mit der Unload-Anweisung im Codebereich der UserForm entladen. Das ist soweit in Ordnung, wenn die weitere Bearbeitung der Eingaben von der UserForm aus ausgeführt wird. Je nach Anwendungsfall kann es jedoch sinnvoll sein, die weitere Bearbeitung der Daten von der Prozedur aus zu steuern, in der sich der Aufruf für das Anzeigen der UserForm befindet. Beispiele dafür wären eine UserForm als InputBox im eigenen Design oder aber auch eine Passwortabfrage. Wer auf Nummer sicher gehen will, vermeidet die Verwendung der von der Anwendung (Excel, Word usw.) erstellten Default-Instanz der UserForm, in unserem Beispiel die UserForm FrmDialog.
Schließen der UserForm verhindern
Um beispielsweise eine UserForm als InputBox verwirklichen zu können, wird die UserForm nicht entladen sondern zunächst nur mit mit der Hide-Methode ausgeblendet. Das heißt also, sowohl die Unload-Anweisungen in den Click-Ereignissen der CommandButtons müssen mit der Hide-Methode ersetzt werden, als auch der Code mit dem QueryClose-Ereignis ergänzt werden.
Immer wieder taucht im Forum die Frage auf, wie man das Schließen-'X' der UserForm deaktivieren oder entfernen kann. Solche "Klimmzüge" wie beispielsweise in den Tipps UserForm Schließen-Schaltfläche deaktivieren und UserForm Schließen-Schaltfläche entfernen sind gar nicht notwendig, denn dafür steht das QueryClose-Ereignis der UserForm zur Verfügung. Wird das Argument Cancel auf True gesetzt, wird der Schließvorgang (Unload-Anweisung) gestoppt. Im Argument CloseMode wird der Grund, für das QueryClose-Ereignis angegeben.
Mit folgendem Beispiel kann die UserForm zum Beispiel nur über Code beendet werden.
 
Private Sub UserForm_QueryClose(Cancel As Integer, _
      CloseMode As Integer)
 'UserForm kann nur über Code beendet werden
  If CloseMode <> vbFormCode Then Cancel = True
End Sub
 
Mit obigem QueryClose-Ereignis weiß der Anwender jedoch nicht "wie ihm geschieht", es ist zwar ein Schließen-'X’ vorhanden, die UserForm wird jedoch nicht geschlossen. Für unser abschließendes Beispiel wollen wir jedoch auf das vom Anwender beabsichtigte Schließen/Abbrechen des Dialogs reagieren.
Ein Anwender kann die Unload-Anweisung auslösen, indem er
im Systemmenü den Befehl Schließen wählt (rechte Maustaste im Titelleiste der UserForm)
auf das Schließen-'X' klickt
oder mit der Tastenkombination Alt+F4 den Dialog abbricht.
Löst der Anwender das Unload-Ereignis aus, in dem er beispielsweise auf der UserForm im Systemmenü den Befehl Schließen gewählt hat, ist der Rückgabewert des Arguments CloseMode gleich 0 bzw. zur besseren Lesbarkeit des Codes gleich der Konstante vbFormControlMenu. In folgendem Beispiel wird das Entladen der UserForm mit der Cancel-Eigenschaft verhindert und die UserForm mit der Hide-Methode ausgeblendet.
 
Private Sub UserForm_QueryClose(Cancel As Integer, _
      CloseMode As Integer)

  If CloseMode = vbFormControlMenu Then
    'Schließen der UserForm verhindern
      Cancel = True
    'UserForm ausblenden
      Me.Hide
    End If
End Sub
 
Wird eine UserForm mit der Hide-Methode ausgeblendet, sollte der Code zum Laden und Anzeigen der UserForm mit der Unload-Anweisung ergänzt werden.
 
Option Explicit

Sub DemoAufruf_4()
1:  Dim objForm As FrmDialog
2:  Set objForm = New FrmDialog
3:  objForm.Show
4:  Unload objForm
5:  Set objForm = Nothing
End Sub
 
Beinahe jeder Dialog wird mit einem OK- oder Übernehmen-Schaltfläche und einer Schaltfläche zum Abbrechen des Vorgangs ausgestattet. Zusätzlich zu den standardmäßig zur Verfügung stehenden Möglichkeiten (das Systemmenü, das Schließen-'X' und die Tastenkombination Alt+F4) einen Dialog abzubrechen, wird auch gerne die Esc-Taste verwendet. Um auf die Esc-Taste reagieren zu können, muss lediglich die Cancel-Eigenschaft des entsprechenden CommandButtons auf True gesetzt werden, damit wird dann automatisch das Click-Ereignis des CommandButtons ausgelöst. Je nach Anwendungsfall sollte auch einem der Schaltflächen die Default-Eigenschaft zugewiesen werden. Damit können die Schaltflächen auch ohne Maus betätigt werden.
Anmerkung: Damit ggf. geänderte Eigenschaften von Steuerelementen nachvollzogen werden können, empfehle ich, diese soweit möglich zur Laufzeit zuzuweisen, z. B. im UserForm_Initialize-Ereignis.
Dialog auswerten
Im letzten Beispiel gilt es festzustellen, ob der Anwender den Dialog mit Klick auf die Schaltfläche OK beendet hat, oder aber den Dialog, wie auch immer, abgebrochen hat.
Je weniger als Public deklarierte Variablen in einem Projekt vorhanden sind desto besser, unter anderem ist auch die Fehlersuche etwas leichter. Um in der aufrufenden Prozedur überprüfen zu können, ob der Dialog mit OK oder Abbrechen beendet wurde, wird hier anstelle einer Public-Variable eine Property-Prozedur verwendet. Weitere Infos dazu können unter Schreiben einer Property-Prozedur in der VB(A)-Hilfe nachgelesen werden.
Code im Codebereich der UserForm
Der hier abgebildete Code im Codebereich der UserForm kann zu jeder beliebigen UserForm hinzugefügt werden, auf dem die Schaltflächen OK oder Übernehmen und Abbrechen hinzugefügt wurden.
 
Option Explicit
Private m_blnCancel  As Boolean

Public Property Get gCancel() As Boolean
  gCancel = m_blnCancel
End Property

Private Sub UserForm_Initialize()
  With Me
    .cmdCancel.Cancel = True
    .cmdOK.Default = True
  End With
End Sub

Private Sub cmdOK_Click()
  m_blnCancel = False
  Me.Hide
End Sub

Private Sub cmdCancel_Click()
  m_blnCancel = True
  Me.Hide
End Sub

Private Sub UserForm_QueryClose(Cancel As Integer, _
      CloseMode As Integer)

  If CloseMode = vbFormControlMenu Then
    Cancel = True
    cmdCancel_Click
  End If
End Sub
 
Code im Modul
 
Option Explicit

Sub DemoAufruf_5()
  Const cMsgTitle As String = "VB-fun-Demo"

  Dim objForm   As FrmDialog
  Dim blnCancel As Boolean

  Set objForm = New FrmDialog
  objForm.Show

  blnCancel = objForm.gCancel

  Unload objForm
  Set objForm = Nothing

  If Not blnCancel Then
      MsgBox "Juhuuuu, der User hat auf OK geklickt!", _
            vbInformation, cMsgTitle
    Else
     'Hier lediglich zur Demo !!!!
      MsgBox "Die Eingabe wurde abgebrochen!", _
            vbInformation, cMsgTitle
    End If
End Sub
 
Eigene Links zum Thema
In den folgenden Tipps wird die UserForm nach dem hier beschriebenen Prinzip aufgerufen, die Initialisierung der UserForm jedoch mit leicht unterschiedlichen Programmiertechniken. In den Tipps werden aber weder globale Variablen verwendet, noch werden die auf der UserForm befindlichen Steuerelemente von "aussen" angesprochen.
Datum suchen (Excel)
InputBox im eigenen Design
Passwort-Abfrage

Ausblick [ Top ]
Wie bereits eingangs geschrieben, ist das Thema UserForms/benutzerdefinierte Dialoge sehr weitläufig.
Geplant ist ein weiterführendes Tutorial, in dem beschrieben wird, wie mehrere Instanzen einer UserForm gleichzeitig verwendet werden können, und wie Daten, die in verschiedenen Dialogen verwendet werden, zwischengespeichert werden können.


Download  (27 kB) Downloads bisher: [ 3891 ]

  Zum Seitenanfang  

Startseite | VB/VBA-Tipps | Projekte | Tutorials | API-Referenz | Komponenten | Bücherecke | VB-/VBA-Forum | VB.Net-Forum | DirectX | DirectX-Forum | Foren-Archiv | VB.Net | Chat | Links | Suchen | Stichwortverzeichnis | Feedback | Impressum

Seite empfehlen Bug-Report
Letzte Aktualisierung: Mittwoch, 15. März 2006