UserForms: Unterschied zwischen den Versionen

Aus VBA-wiki
Zur Navigation springen Zur Suche springen
(Die Seite wurde neu angelegt: „Zusätzlich zu den eingebauten Dialogen bietet VBA die Möglichkeit, eigene Dialoge zu erstellen. Diese werden 'UserForms' genannt und stellen eine Sonderform…“)
 
Keine Bearbeitungszusammenfassung
 
(4 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt)
Zeile 1: Zeile 1:
[[Category:vba-wiki]]
Zusätzlich zu den eingebauten Dialogen bietet VBA die Möglichkeit, eigene Dialoge zu erstellen. Diese werden 'UserForms' genannt und stellen eine Sonderform von Klassen dar.
Zusätzlich zu den eingebauten Dialogen bietet VBA die Möglichkeit, eigene Dialoge zu erstellen. Diese werden 'UserForms' genannt und stellen eine Sonderform von Klassen dar.
== Einsatz von Dialogen ==
Prinzipiell können wir zwischen drei Dialogtypen unterscheiden, die in unserer VBA-Programmierung relevant sind:
* Mitteilung / einfache Entscheidung: Dem Anwender wird eine Nachricht angezeigt (MessageBox) oder eine Frage gestellt, die eindeutig beantwortet werden kann (Messagebox mit mehrern Knöpfen).<br>'''Beispiele:'''
MsgBox "Aufgabe erfolgreich erfüllt"
blnContinue = MsgBox("Soll dieser Schritt ausgeführt werden?", vbYesNo)
* Eingabe: Der Anwender kann mehrere Daten ändern und den Dialog bestätigen oder den Vorgang abbrechen.<br>'''Beispiele:''' Eingabe / Bearbeitung von Daten, Einstellungen etc.
* Komplexe Arbeitsschritte: Ein Dialog (oder mehrere Dialoge) führen durch einen komplexen / über mehrere Schritte verteilten Vorgang.<br>'''Beispiele:''' Seriendruck in Word
In diesem Kapitel werden wir uns ausschließlich mit Eingabedialogen befassen.


== Trennung von Darstellung und Logik ==
== Trennung von Darstellung und Logik ==


Um den Überblick zu behalten und den Programmfluss optimal zu gestalten, sollte zwischen Darstellung (dem im Dialog Gezeigten) und der Logik (der Programmierung) eine Trennung erfolgen. Diese Trennung kann anhand des Datei-Dialogs veranschaulicht werden: <span style="Color:#0000FF;">Private Function </span>BrowseToPath() <span style="Color:#0000FF;">As </span>String <span style="Color:#0000FF;">Dim </span>dlg <span style="Color:#0000FF;">As </span>FileDialog <span style="Color:#0000FF;">Set </span>dlg <span style="Color:#993300;">= </span>Application.FileDialog(msoFileDialogFolderPicker) dlg.Title <span style="Color:#993300;">=</span> <span style="Color:#808080;">"Zielverzeichnis wählen"</span> dlg.InitialFileName <span style="Color:#993300;">=</span> <span style="Color:#808080;">"C:\temp\"</span> dlg.Show <span style="Color:#0000FF;">If </span>dlg.SelectedItems.Count <span style="Color:#993300;">></span> <span style="Color:#00FFFF;">0 </span>Then BrowseToPath <span style="Color:#993300;">= </span>dlg.SelectedItems.Item(<span style="Color:#00FFFF;">1</span>) <span style="Color:#0000FF;">End If</span> <span style="Color:#0000FF;">End Function</span>
Um den Überblick zu behalten und den Programmfluss optimal zu gestalten, sollte zwischen Darstellung (dem im Dialog Gezeigten) und der Logik (der Programmierung) eine Trennung erfolgen.
 
Diese Trennung kann anhand des eingebauten Datei-Dialogs veranschaulicht werden:
 
<span style="Color:#0000FF;">Public Function </span>BrowseToPath() <span style="Color:#0000FF;">As </span>String
    <span style="Color:#0000FF;">Dim </span>dlg <span style="Color:#0000FF;">As </span>FileDialog
   
    <span style="Color:#0000FF;">Set </span>dlg <span style="Color:#993300;">= </span>Application.FileDialog(msoFileDialogFolderPicker)
    dlg.Title <span style="Color:#993300;">=</span> <span style="Color:#808080;">"Zielverzeichnis wählen"</span>
    dlg.InitialFileName <span style="Color:#993300;">=</span> <span style="Color:#808080;">"C:\temp\"</span>
    dlg.Show
    <span style="Color:#0000FF;">If </span>dlg.SelectedItems.Count <span style="Color:#993300;">></span> <span style="Color:#00FFFF;">0 </span>Then
        BrowseToPath <span style="Color:#993300;">= </span>dlg.SelectedItems.Item(<span style="Color:#00FFFF;">1</span>)
    <span style="Color:#0000FF;">End If</span>
<span style="Color:#0000FF;">End Function</span>
 
* Eine Steuerprozedur (die Funktion 'BrowseToPath') fasst alle zur Anzeige und Auswertung des Dialogs benötigten Schritte zusammen.
* Eine Steuerprozedur (die Funktion 'BrowseToPath') fasst alle zur Anzeige und Auswertung des Dialogs benötigten Schritte zusammen.
* Die Anzeige des Dialogs erfolgt in vier Schritten: 1. Eine Variable wird deklariert und mit dem gewünschten Dialog instanziiert: <span style="Color:#0000FF;">Dim </span>dlg <span style="Color:#0000FF;">As </span>FileDialog <span style="Color:#0000FF;">Set </span>dlg <span style="Color:#993300;">= </span>Application.FileDialog(msoFileDialogFolderPicker) 2. Der Dialog wird für die Anzeige vorbereitet: dlg.Title <span style="Color:#993300;">=</span> <span style="Color:#808080;">"Zielverzeichnis wählen"</span> dlg.InitialFileName <span style="Color:#993300;">=</span> <span style="Color:#808080;">"C:\temp\"</span> 3. Der Dialog wird angezeigt: dlg.Show 4. Die Benutzeringabe wird ausgewertet: <span style="Color:#0000FF;">If </span>dlg.SelectedItems.Count <span style="Color:#993300;">></span> <span style="Color:#00FFFF;">0 </span>Then BrowseToPath <span style="Color:#993300;">= </span>dlg.SelectedItems.Item(<span style="Color:#00FFFF;">1</span>) <span style="Color:#0000FF;">End If</span> Die Steuerprozedur ist demnach größtenteils für die Vorbereitung des Dialogs und die Reaktion auf / die Auswertung der Benutzereingaben beschäftigt. Die Erstellung des Dialogs und dessen Anzeige ergeben sich aus den Hauptaufgaben. Wenn wir dieses System auf selbst erstellte Dialoge anwenden, ergeben sich folgende Schritte:
* Die Anzeige des Dialogs erfolgt in vier Schritten:
 
1. Eine Variable wird deklariert und mit dem gewünschten Dialog instanziiert:
 
    <span style="Color:#0000FF;">Dim </span>dlg <span style="Color:#0000FF;">As </span>FileDialog
   
    <span style="Color:#0000FF;">Set </span>dlg <span style="Color:#993300;">= </span>Application.FileDialog(msoFileDialogFolderPicker)
 
 
2. Der Dialog wird für die Anzeige vorbereitet:
 
    dlg.Title <span style="Color:#993300;">=</span> <span style="Color:#808080;">"Zielverzeichnis wählen"</span>
    dlg.InitialFileName <span style="Color:#993300;">=</span> <span style="Color:#808080;">"C:\temp\"</span>
 
3. Der Dialog wird angezeigt:
 
    dlg.Show
 
4. Die Benutzeringabe wird ausgewertet:
 
      <span style="Color:#0000FF;">If </span>dlg.SelectedItems.Count <span style="Color:#993300;">></span> <span style="Color:#00FFFF;">0 </span>Then
          BrowseToPath <span style="Color:#993300;">= </span>dlg.SelectedItems.Item(<span style="Color:#00FFFF;">1</span>)
      <span style="Color:#0000FF;">End If</span>
 
Die Steuerprozedur ist demnach größtenteils für die Vorbereitung des Dialogs und die Reaktion auf / die Auswertung der Benutzereingaben beschäftigt. Die Erstellung des Dialogs und dessen Anzeige ergeben sich aus den Hauptaufgaben.
 
Wenn wir dieses System auf selbst erstellte Eingabedialoge anwenden, ergeben sich folgende Schritte:


=== Dialog (UserForm) ===
=== Dialog (UserForm) ===


{| class="wikitable"
{| class="wikitable"  
! style="text-align:left;" | &nbsp;
! style="text-align:left;" | &nbsp;
! style="text-align:left;" | Arbeitsschritt
! style="text-align:left;" | Arbeitsschritt
Zeile 15: Zeile 69:
|- style="vertical-align:top;"
|- style="vertical-align:top;"
| 1
| 1
| '''Dialog aufbauen''' |
| '''Dialog aufbauen'''
|
|- style="vertical-align:top;"
|- style="vertical-align:top;"
| 1a
| 1a
| Gestaltung des Dialogs (Anlegen und Platzierung der Elemente wie Beschriftungsfelder, Eingabefelder und Knöpfe). |
| Gestaltung des Dialogs (Anlegen und Platzierung der Elemente wie Beschriftungsfelder, Eingabefelder und Knöpfe).
|
|- style="vertical-align:top;"
|- style="vertical-align:top;"
| 1b
| 1b
| Sinnvolle Benennung der Elemente ('frmUserData', 'lblFirstName', 'txtFirstName', 'cmbOK', ...) vornehmen. |
| Sinnvolle Benennung der Elemente ('frmUserData', 'lblFirstName', 'txtFirstName', 'cmbOK', ...) vornehmen.
|
|- style="vertical-align:top;"
|- style="vertical-align:top;"
| 2
| 2
| '''Ereignisse einsetzen''' |
| '''Ereignisse einsetzen'''
|
|- style="vertical-align:top;"
|- style="vertical-align:top;"
| 2a
| 2a
| Das Klicken auf den OK-Knopf soll lediglich den Dialog verbergen, damit die Benutzereingaben ausgewertet werden können. Der Befehl 'Me.Hide' gibt die Befehlsgewalt direkt an die Prozedur zurück, welche 'myDialog.Show' aufgerufen hat.
| Das Klicken auf den OK-Knopf soll lediglich den Dialog verbergen, damit die Benutzereingaben ausgewertet werden können. Der Befehl 'Me.Hide' gibt die Befehlsgewalt direkt an die Prozedur zurück, welche 'myDialog.Show' aufgerufen hat.
| <span style="Color:#0000FF;">Private Sub </span>cmbOK_Click() Me.Hide <span style="Color:#0000FF;">End Sub</span>
|
<span style="Color:#0000FF;">Private Sub </span>cmbOK_Click()
   
    Me.Hide
<span style="Color:#0000FF;">End Sub</span>
|- style="vertical-align:top;"
|- style="vertical-align:top;"
| 2b
| 2b
| Das Klicken auf den Abbrechen-Knopf soll ebenfalls den Dialog verbergen, aber zusätzlich signalisieren, dass der Vorgang abgebrochen wurde. Zusätzlich benötigen wir hierfür eine öffentliche Variable, damit die Steuerprozedur später diesen Wert abrufen kann.
| Das Klicken auf den Abbrechen-Knopf soll ebenfalls den Dialog verbergen, aber zusätzlich signalisieren, dass der Vorgang abgebrochen wurde. Zusätzlich benötigen wir hierfür eine öffentliche Variable, damit die Steuerprozedur später diesen Wert abrufen kann.
| <span style="Color:#0000FF;">Public </span>CancelWasPressed <span style="Color:#0000FF;">As </span>Boolean <span style="Color:#0000FF;">Private Sub </span>cmbCancel_Click() CancelWasPressed <span style="Color:#993300;">= </span>True Me.Hide <span style="Color:#0000FF;">End Sub</span> '''Achtung:''' Globale Variablen (hier 'Public CancelWasPressed As Boolean') müssen immer vor allen Prozeduren, am besten unter 'Option Explicit', deklariert werden!
|  
<span style="Color:#0000FF;">Public </span>CancelWasPressed <span style="Color:#0000FF;">As </span>Boolean  
 
<span style="Color:#0000FF;">Private Sub </span>cmbCancel_Click()
     
    CancelWasPressed <span style="Color:#993300;">= </span>True
    Me.Hide  
<span style="Color:#0000FF;">End Sub</span>
 
'''Achtung:''' Globale Variablen (hier 'Public CancelWasPressed As Boolean') müssen immer vor allen Prozeduren, am besten unter 'Option Explicit', deklariert werden!
|- style="vertical-align:top;"
|- style="vertical-align:top;"
| 2c
| 2c
| Um das Beenden mit dem roten 'x' später als Abbruch des Dialogs auswerten zu können, benötigen Sie zusätzlich das UserForm-Ereignis 'Terminate', um auch hier die öffentliche Variable 'CancelWasPressed' auf 'True' zu setzen.
| Um das Beenden mit dem roten 'x' später als Abbruch des Dialogs auswerten zu können, benötigen Sie zusätzlich das UserForm-Ereignis 'Terminate', um auch hier die öffentliche Variable 'CancelWasPressed' auf 'True' zu setzen.
| <span style="Color:#0000FF;">Private Sub </span>UserForm_Terminate() CancelWasPressed <span style="Color:#993300;">= </span>True <span style="Color:#0000FF;">End Sub</span>
|  
<span style="Color:#0000FF;">Private Sub </span>UserForm_Terminate()
   
    CancelWasPressed <span style="Color:#993300;">= </span>True
<span style="Color:#0000FF;">End Sub</span>
|- style="vertical-align:top;"
|- style="vertical-align:top;"
| 3
| 3
| '''Dialog füllen und auslesen''' |
| '''Dialog füllen und auslesen'''
|  
|- style="vertical-align:top;"
|- style="vertical-align:top;"
| 3a
| 3a
| Eine Prozedur ermöglicht es, dem Dialog die gewünschten Daten und Einstellungen für die Anzeige zu übergeben.
| Eine Prozedur ermöglicht es, dem Dialog die gewünschten Daten und Einstellungen für die Anzeige zu übergeben.  
| Einfache Übernahme von einem Wert: <span style="Color:#0000FF;">Public Sub </span>LoadName(<span style="Color:#0000FF;">ByVal </span>strName <span style="Color:#0000FF;">As </span>String) Me.txtName.Text <span style="Color:#993300;">= </span>strName <span style="Color:#0000FF;">End Sub</span> Übernahme von mehreren Werten aus einem benutzerdefinierten Datentyp 'Type': <span style="Color:#0000FF;">Public Sub </span>LoadData(<span style="Color:#0000FF;">ByVal </span>thisData <span style="Color:#0000FF;">As </span>tpeDialogData) Me.txtFirstName.Text <span style="Color:#993300;">= </span>thisData.FirstName Me.txtLastName.Text <span style="Color:#993300;">= </span>thisData.LastName <span style="Color:#008000;">' ...</span> <span style="Color:#0000FF;">End Sub</span>
| Einfache Übernahme von einem Wert:
 
<span style="Color:#0000FF;">Public Sub </span>LoadName(<span style="Color:#0000FF;">ByVal </span>strName <span style="Color:#0000FF;">As </span>String)
     
    Me.txtName.Text <span style="Color:#993300;">= </span>strName
<span style="Color:#0000FF;">End Sub</span>
 
Übernahme von mehreren Werten aus einem benutzerdefinierten Datentyp 'Type':
 
<span style="Color:#0000FF;">Public Sub </span>LoadData(<span style="Color:#0000FF;">ByVal </span>thisData <span style="Color:#0000FF;">As </span>tpeDialogData)
     
    Me.txtFirstName.Text <span style="Color:#993300;">= </span>thisData.FirstName
    Me.txtLastName.Text <span style="Color:#993300;">= </span>thisData.LastName
    <span style="Color:#008000;">' ...</span>
<span style="Color:#0000FF;">End Sub</span>
|- style="vertical-align:top;"
|- style="vertical-align:top;"
| 3b
| 3b
| Eine Funktion ermöglicht das Auslesen der vom Benutzer eingegebenen Werte.
| Eine Funktion ermöglicht das Auslesen der vom Benutzer eingegebenen Werte.
| Einfaches Auslesen eines Wertes: <span style="Color:#0000FF;">Public Function </span>ReturnName() <span style="Color:#0000FF;">As </span>String ReturnName <span style="Color:#993300;">= </span>Me.txtName.Text <span style="Color:#0000FF;">End Function</span> Auslesen mehrerer Werte mithilfe eines benutzerdefinierten Datentyps 'Type': <span style="Color:#0000FF;">Public Function </span>ReturnData() <span style="Color:#0000FF;">As </span>tpeDialogData) ReturnDataMe.FirstName <span style="Color:#993300;">= </span>txtFirstName.Text ReturnDataMe.LastName <span style="Color:#993300;">= </span>txtLastName.Text <span style="Color:#008000;">' ...</span> <span style="Color:#0000FF;">End Function</span>  
| Einfaches Auslesen eines Wertes:
<span style="Color:#0000FF;">Public Function </span>ReturnName() <span style="Color:#0000FF;">As </span>String
     
    ReturnName <span style="Color:#993300;">= </span>Me.txtName.Text
<span style="Color:#0000FF;">End Function</span>
 
Auslesen mehrerer Werte mithilfe eines benutzerdefinierten Datentyps 'Type':
 
<span style="Color:#0000FF;">Public Function </span>ReturnData() <span style="Color:#0000FF;">As </span>tpeDialogData)
     
    ReturnDataMe.FirstName <span style="Color:#993300;">= </span>txtFirstName.Text  
    ReturnDataMe.LastName <span style="Color:#993300;">= </span>txtLastName.Text  
    <span style="Color:#008000;">' ...</span>
<span style="Color:#0000FF;">End Function</span>
|}
|}


=== Steuerprozedur ===
Die Steuerprozedur übernimmt den Aufruf und die Kontrolle über den Dialog. Sie sorgt dafür, dass der Dialog die benötigten Daten erhält, damit er diese anzeigen kann, sie ruft den Dialog auf und sie liest anschließend die eingegebenen Daten aus und verarbeitet diese weiter.


=== Steuerprozedur ===
Die Steuerprozedur kann auch eine Funktion sein, welche die Vorgabewerte als Parameter übernimmt und anschließend die Benutzereingabe als Rückgabewert zurück gibt.


Die Steuerprozedur übernimmt den Aufruf und die Kontrolle über den Dialog. Sie sorgt dafür, dass der Dialog die benötigten Daten erhält, damit er diese anzeigen kann, sie ruft den Dialog auf und sie liest anschließend die eingegebenen Daten aus und verarbeitet diese weiter. Die Steuerprozedur kann auch eine Funktion sein, welche die Vorgabewerte als Parameter übernimmt und anschließend die Benutzereingabe als Rückgabewert zurück gibt.
{| class="wikitable"  
{| class="wikitable"
! style="text-align:left;" | &nbsp;
! style="text-align:left;" | &nbsp;
! style="text-align:left;" | Arbeitsschritt
! style="text-align:left;" | Arbeitsschritt
Zeile 60: Zeile 165:
|- style="vertical-align:top;"
|- style="vertical-align:top;"
| 1
| 1
| '''Vorbereitung''' |
| '''Vorbereitung'''
|  
|- style="vertical-align:top;"
|- style="vertical-align:top;"
| 1&nbsp;a
| 1&nbsp;a
| Eine Variable zur Erstellung des Dialogs wird deklariert.
| Eine Variable zur Erstellung des Dialogs wird deklariert.
| <span style="Color:#0000FF;">Dim </span>myDialog <span style="Color:#0000FF;">As </span>frmDialog
|  
      <span style="Color:#0000FF;">Dim </span>myDialog <span style="Color:#0000FF;">As </span>frmDialog
|- style="vertical-align:top;"
|- style="vertical-align:top;"
| 1&nbsp;b
| 1&nbsp;b
| Die Variable wird mit 'New' instanziiert. Das Schlüsselwort 'New' sorgt dafür, dass keine vorherige Instanz des Dialoges verwendet wird. Siehe [[VBA_Syntax_und_Sprachelemente#New|New]].
| Die Variable wird mit 'New' instanziiert.
| <span style="Color:#0000FF;">Set </span>myDialog <span style="Color:#993300;">= </span>New frmDialog
 
Das Schlüsselwort 'New' sorgt dafür, dass keine vorherige Instanz des Dialoges verwendet wird. Siehe [[VBA_Syntax_und_Sprachelemente#New|New]].  
|  
    <span style="Color:#0000FF;">Set </span>myDialog <span style="Color:#993300;">= </span>New frmDialog
|- style="vertical-align:top;"
|- style="vertical-align:top;"
| 2
| 2
| '''Optional:''' Die Ausgangsdaten werden an den Dialog übergeben. Hierzu wird die entsprechende Prozedur im Dialog aufgerufen. Dieser Schritt wird nur benötigt, wenn Sie für die Anzeige des Dialogs zusätzliche Informationen benötigen oder Voreinträge machen möchten.
| '''Optional:''' Die Ausgangsdaten werden an den Dialog übergeben. Hierzu wird die entsprechende Prozedur im Dialog aufgerufen. Dieser Schritt wird nur benötigt, wenn Sie für die Anzeige des Dialogs zusätzliche Informationen benötigen oder Voreinträge machen möchten.
| myDialog.LoadName strName
|  
    myDialog.LoadName strName
|- style="vertical-align:top;"
|- style="vertical-align:top;"
| 3
| 3
| Der Dialog wird angezeigt.
| Der Dialog wird angezeigt.
| myDialog.Show
|
    myDialog.Show
 
|- style="vertical-align:top;"
|- style="vertical-align:top;"
| 4&nbsp;a
| 4&nbsp;a
| Wenn der Anwender nach der Anzeige mit 'Show' den Dialog schließt, kehrt die Ausführung in die Steuerprozedur zurück. Nun müssen wir klären, ob der Anwender 'Abbrechen' bzw. das rote 'X' oder 'OK' gewählt hat. Wurde der Dialog abgebrochen, soll damit in der Regel der weitere Verlauf der Prozedur ebenfalls abgebrochen werden.
| Wenn der Anwender nach der Anzeige mit 'Show' den Dialog schließt, kehrt die Ausführung in die Steuerprozedur zurück. Nun müssen wir klären, ob der Anwender 'Abbrechen' bzw. das rote 'X' oder 'OK' gewählt hat. Wurde der Dialog abgebrochen, soll damit in der Regel der weitere Verlauf der Prozedur ebenfalls abgebrochen werden.
| <span style="Color:#0000FF;">If </span>myDialog.CancelWasPressed <span style="Color:#993300;">= </span><span style="Color:#0000FF;">True Then Exit Sub</span>
|  
      <span style="Color:#0000FF;">If </span>myDialog.CancelWasPressed <span style="Color:#993300;">= </span><span style="Color:#0000FF;">True Then Exit Sub</span>
|- style="vertical-align:top;"
|- style="vertical-align:top;"
| 4&nbsp;b
| 4&nbsp;b
| Der Dialog wird anschließend ausgewertet, also die Eingabe(n) des Anwenders abgefragt.
| Der Dialog wird anschließend ausgewertet, also die Eingabe(n) des Anwenders abgefragt.
| strName <span style="Color:#993300;">= </span>myDialog.ReturnName  
|  
    strName <span style="Color:#993300;">= </span>myDialog.ReturnName
|}
|}
;Beispiele einer Steuerprozedur:
 
* Als Sub-Prozedur: <span style="Color:#0000FF;">Private Sub </span>ShowDialog() <span style="Color:#0000FF;">Dim </span>strName <span style="Color:#0000FF;">As String</span> <span style="Color:#0000FF;">Dim </span>myDialog <span style="Color:#0000FF;">As </span>frmDialog <span style="Color:#0000FF;">Set </span>myDialog <span style="Color:#993300;">= </span>New frmDialog myDialog.LoadData myDialog.Show <span style="Color:#0000FF;">If </span>myDialog.CancelWasPressed <span style="Color:#993300;">= </span>False Then strName <span style="Color:#993300;">= </span>myDialog.ReturnName Debug.Print strName <span style="Color:#0000FF;">End If</span> <span style="Color:#0000FF;">End Sub</span>
;Beispiele einer Steuerprozedur:
* Als Funktion: <span style="Color:#0000FF;">Public Function </span>EnterName()<span style="Color:#0000FF;"> As </span>String <span style="Color:#0000FF;">Dim </span>myDialog <span style="Color:#0000FF;">As </span>frmDialog <span style="Color:#0000FF;">Set </span>myDialog <span style="Color:#993300;">= </span>New frmDialog myDialog.LoadData myDialog.Show <span style="Color:#0000FF;">If </span>myDialog.CancelWasPressed <span style="Color:#993300;">= </span>False Then EnterName <span style="Color:#993300;">= </span>myDialog.ReturnName <span style="Color:#0000FF;">End If</span> <span style="Color:#0000FF;">End Function</span>
* Als Sub-Prozedur:
 
<span style="Color:#0000FF;">Public Sub </span>ShowDialog()  
      <span style="Color:#0000FF;">Dim </span>strName <span style="Color:#0000FF;">As String</span>
      <span style="Color:#0000FF;">Dim </span>myDialog <span style="Color:#0000FF;">As </span>frmDialog
     
      <span style="Color:#0000FF;">Set </span>myDialog <span style="Color:#993300;">= </span>New frmDialog
      myDialog.LoadData
      myDialog.Show
      <span style="Color:#0000FF;">If </span>myDialog.CancelWasPressed <span style="Color:#993300;">= </span>False Then
          strName <span style="Color:#993300;">= </span>myDialog.ReturnName
          Debug.Print strName
      <span style="Color:#0000FF;">End If</span>
<span style="Color:#0000FF;">End Sub</span>
 
* Als Funktion:
 
<span style="Color:#0000FF;">Public Function </span>EnterName()<span style="Color:#0000FF;"> As </span>String  
      <span style="Color:#0000FF;">Dim </span>myDialog <span style="Color:#0000FF;">As </span>frmDialog
     
      <span style="Color:#0000FF;">Set </span>myDialog <span style="Color:#993300;">= </span>New frmDialog
      myDialog.LoadData
      myDialog.Show
      <span style="Color:#0000FF;">If </span>myDialog.CancelWasPressed <span style="Color:#993300;">= </span>False Then
          EnterName <span style="Color:#993300;">= </span>myDialog.ReturnName
      <span style="Color:#0000FF;">End If</span>
<span style="Color:#0000FF;">End Function</span>


== Intuitive Bedienung ==
== Intuitive Bedienung ==
Zeile 96: Zeile 237:
=== OK-Knopf ===
=== OK-Knopf ===


Folgende Eigenschaft des OK-Knopfes sorgt dafür, dass bei der Betätigung der Eingabetaste (Enter, Return) der Dialog bestätigt wird, indem diese direkt an den OK-Knopf übergeben wird: Default = True
Folgende Eigenschaft des OK-Knopfes sorgt dafür, dass bei der Betätigung der Eingabetaste (Enter, Return) der Dialog bestätigt wird, indem diese direkt an den OK-Knopf übergeben wird:
 
Default <span style="Color:gray">=</span><span style="Color:blue"> True</span>


=== Abbrechen-Knopf ===
=== Abbrechen-Knopf ===


Folgende Eigenschaft des Abbrechen-Knopfes sorgt dafür, dass bei der Betätigung der Escabe-Taste der Dialog abgebrochen wird, indem diese direkt an den Abbrechen-Knopf übergeben wird: Cancel = True
Folgende Eigenschaft des Abbrechen-Knopfes sorgt dafür, dass bei der Betätigung der Escabe-Taste der Dialog abgebrochen wird, indem diese direkt an den Abbrechen-Knopf übergeben wird:
 
Cancel <span style="Color:gray">=</span><span style="Color:blue"> True</span>


=== Markierung des ersten Eingabefeldes ===
=== Markierung des ersten Eingabefeldes ===


Um beim Starten des Dialogs das erste Eingabefeld zu markieren (damit der Anwender lediglich durch Eingabe eines Textes den ursprünglichen Wert überschreiben kann, ohne diesen erst löschen zu müssen), können Sie das 'Activate'-Ereignis der UserForm wie folgt erweitern: Private Sub UserForm_Activate() txtFirst.SetFocus txtFirst.SelStart = 0 txtFirst.SelLength = Len(Me.txtFirst.Text) End Sub
Um beim Starten des Dialogs das erste Eingabefeld zu markieren (damit der Anwender lediglich durch Eingabe eines Textes den ursprünglichen Wert überschreiben kann, ohne diesen erst löschen zu müssen), können Sie das 'Activate'-Ereignis der UserForm wie folgt erweitern:
 
<span style="Color:blue">Private Sub </span>UserForm_Activate<span style="Color:gray">()</span>
   
    txtFirst<span style="Color:gray">.</span>SetFocus
    txtFirst<span style="Color:gray">.</span>SelStart <span style="Color:gray">=</span> <span style="Color:gray">0</span>
    txtFirst<span style="Color:gray">.</span>SelLength <span style="Color:gray">=</span> Len<span style="Color:gray">(</span>Me<span style="Color:gray">.</span>txtFirst<span style="Color:gray">.</span>Text<span style="Color:gray">)</span>
<span style="Color:blue">End Sub</span>


=== Reihenfolge (TabIndex) ===
=== Reihenfolge (TabIndex) ===


Die Reihenfolge beim Ausfüllen von Dialogen (durch Betätigung der Tabulator-Taste) wird mit der 'TabIndex'-Eigenschaft der Elemente bestimmt. Wenn Sie die Eingabefelder in der gewünschten Reihenfolge angelegt haben, müssen Sie diese in der Regel nicht nachbearbeiten. Wenn Sie jedoch nachträglich weitere Felder hinzufügen oder die Reihenfolge ändern, sollten Sie den Dialog daraufhin prüfen und die 'TabIndex'-Eigenschaft entsprechend anpassen. '''Bitte beachten:''' Der erste TabIndex beträgt 0, alle weiteren werden um einen Index erhöht. Wenn Sie einen schon vorhandenen Index neu vergeben, erhält das Element mit dem doppelten Index einen neuen Index. '''Bitte beachten:''' Der 'TabIndex' wird nicht beachtet, wenn die Eigenschaft 'TabStop' nicht 'True' ist! '''Tipp:''' Die 'SetDefaultTabOrder'-Methode des UserForms weist allen Elementen des Dialogs eine neue Reihenfolge zu, die von links nach rechts und oben nach unten erfolgt. <span style="Color:#0000FF;">Private Sub </span>UserForm_Activate() Me.SetDefaultTabOrder <span style="Color:#0000FF;">End Sub</span>
Die Reihenfolge beim Ausfüllen von Dialogen (durch Betätigung der Tabulator-Taste) wird mit der 'TabIndex'-Eigenschaft der Elemente bestimmt. Wenn Sie die Eingabefelder in der gewünschten Reihenfolge angelegt haben, müssen Sie diese in der Regel nicht nachbearbeiten. Wenn Sie jedoch nachträglich weitere Felder hinzufügen oder die Reihenfolge ändern, sollten Sie den Dialog daraufhin prüfen und die 'TabIndex'-Eigenschaft entsprechend anpassen.
 
'''Bitte beachten:''' Der erste TabIndex beträgt 0, alle weiteren werden um einen Index erhöht. Wenn Sie einen schon vorhandenen Index neu vergeben, erhält das Element mit dem doppelten Index einen neuen Index.
 
'''Bitte beachten:''' Der 'TabIndex' wird nicht beachtet, wenn die Eigenschaft 'TabStop' nicht 'True' ist!
 
'''Tipp:''' Die 'SetDefaultTabOrder'-Methode des UserForms weist allen Elementen des Dialogs eine neue Reihenfolge zu, die von links nach rechts und oben nach unten erfolgt.
 
<span style="Color:#0000FF;">Private Sub </span>UserForm_Activate()
   
    Me.SetDefaultTabOrder
<span style="Color:#0000FF;">End Sub</span>


=== Eingabe zulassen / unterdrücken ===
=== Eingabe zulassen / unterdrücken ===


Wenn Sie ausschließlich die Eingabe von vorgegebenen Zeichen in ein Eingabefeld (TextBox) zulassen möchten (zum Beispiel zur Eingabe einer Telefonnummer), können Sie das 'KeyPress'-Ereignis wie folgt einsetzen: Private Sub txtTextbox_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger) ' Eingabe von nur diesen Zeichen zulassen If '''Not''' Chr(KeyAscii) Like "[0-9./+ -]" Then Beep ' Gibt einen Warnton aus KeyAscii = 0 End If End Sub Wenn Sie die Eingabe von bestimmten Zeichen unterdrücken möchten, können Sie wie folgt vorgehen: Private Sub txtValue_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger) ' Eingabe von diesen Zeichen unterdrücken If Chr(KeyAscii) Like "[.:-]" Then Beep ' Gibt einen Warnton aus KeyAscii = 0 End If End Sub
Wenn Sie ausschließlich die Eingabe von vorgegebenen Zeichen in ein Eingabefeld (TextBox) zulassen möchten (zum Beispiel zur Eingabe einer Telefonnummer), können Sie das 'KeyPress'-Ereignis wie folgt einsetzen:
 
Private Sub txtTextbox_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger)
    ' Eingabe von nur diesen Zeichen zulassen
    If '''Not''' Chr(KeyAscii) Like "[0-9./+ -]" Then
        Beep             ' Gibt einen Warnton aus
        KeyAscii = 0
    End If
End Sub
 
Wenn Sie die Eingabe von bestimmten Zeichen unterdrücken möchten, können Sie wie folgt vorgehen:
 
Private Sub txtValue_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger)
   
    ' Eingabe von diesen Zeichen unterdrücken
    If Chr(KeyAscii) Like "[.:-]" Then
        Beep             ' Gibt einen Warnton aus
        KeyAscii = 0
    End If
End Sub


== Elemente einer UserForm (Controls) ==
== Elemente einer UserForm (Controls) ==


=== Listenfeld und Kombinationsfeld (ListBox und Combobox)=== Das Listenfeld und das Kombinationsfeld sind sehr stark miteinander verwandt, denn beide stellen Datenreihen als Liste bzw. Tabelle dar. Der größte Unterschied ist die Darstellung: Das Listenfeld ist ein immer aufgeklapptes Kombinationsfeld, das Kombinationsfeld ein Listenfeld, bei dem nur der erste (bzw. gewählte) Eintrag sichtbar ist -- die weiteren Einträge können bei Bedarf sichtbar gemacht werden.
=== Listenfeld und Kombinationsfeld (ListBox und Combobox)===
 
Das Listenfeld und das Kombinationsfeld sind sehr stark miteinander verwandt, denn beide stellen Datenreihen als Liste bzw. Tabelle dar. Der größte Unterschied ist die Darstellung: Das Listenfeld ist ein immer aufgeklapptes Kombinationsfeld, das Kombinationsfeld ein Listenfeld, bei dem nur der erste (bzw. gewählte) Eintrag sichtbar ist -- die weiteren Einträge können bei Bedarf sichtbar gemacht werden.


==== Listenfeld und Kombinationsfeld mit Daten füllen ====
==== Listenfeld und Kombinationsfeld mit Daten füllen ====


Hierfür stehen insgesamt zwei (bei Excel drei) Wege zur Verfügung:
Hierfür stehen insgesamt zwei (bei Excel drei) Wege zur Verfügung:  


===== Aus einem Array =====
===== Aus einem Array =====


Wenn die Daten in Form eines Arrays vorliegen, können sie direkt in die 'List'-Eigenschaft übernommen werden: <span style="Color:#0000FF;">Public Sub </span>LoadData(<span style="Color:#0000FF;">ByRef </span>strItems() <span style="Color:#0000FF;">As </span>String) lbxListBox.List <span style="Color:#993300;">= </span>strItems cboComboBox.List <span style="Color:#993300;">= </span>strItems <span style="Color:#0000FF;">End Sub</span> '''Bitte beachten:''' Wenn ein mehrspaltiges Array übergeben wird, muss die 'ColumnCount'-Eigenschaft verwendet werden, um die zusätzlichen Spalten darzustellen.
Wenn die Daten in Form eines Arrays vorliegen, können sie direkt in die 'List'-Eigenschaft übernommen werden:
 
<span style="Color:#0000FF;">Public Sub </span>LoadData(<span style="Color:#0000FF;">ByRef </span>strItems() <span style="Color:#0000FF;">As </span>String)
    lbxListBox.List <span style="Color:#993300;">= </span>strItems
    cboComboBox.List <span style="Color:#993300;">= </span>strItems
<span style="Color:#0000FF;">End Sub</span>
 
'''Bitte beachten:''' Wenn ein mehrspaltiges Array übergeben wird, muss die 'ColumnCount'-Eigenschaft verwendet werden, um die zusätzlichen Spalten darzustellen.


===== Einzelne Elemente hinzufügen =====
===== Einzelne Elemente hinzufügen =====


Wenn die Daten als Collection vorliegen, können sie einzeln per 'AddItem' hinzugefügt werden: <span style="Color:#0000FF;">Public Sub </span>LoadData(<span style="Color:#0000FF;">ByVal </span>colItems <span style="Color:#0000FF;">As </span>Collection) <span style="Color:#0000FF;">Dim </span>lngIndex <span style="Color:#0000FF;">As </span>Long <span style="Color:#0000FF;">For </span>lngIndex <span style="Color:#993300;">=</span> <span style="Color:#00FFFF;">1</span> <span style="Color:#0000FF;">To </span>colItems.Count lbxListBox.AddItem colItems.Item(lngIndex) cboComboBox.AddItem colItems.Item(lngIndex) <span style="Color:#0000FF;">Next </span>lngIndex <span style="Color:#0000FF;">End Sub</span> Ebenso können einzelne Elemente, die nicht aus einer Collection stammen, zur Laufzeit immer wieder hinzugefügt werden. Public Sub AddItem(ByVal strItem As String) lbxListBox.AddItem strItem cboComboBox.AddItem strItem End Sub
Wenn die Daten als Collection vorliegen, können sie einzeln per 'AddItem' hinzugefügt werden:
 
<span style="Color:#0000FF;">Public Sub </span>LoadData(<span style="Color:#0000FF;">ByVal </span>colItems <span style="Color:#0000FF;">As </span>Collection)
    <span style="Color:#0000FF;">Dim </span>lngIndex <span style="Color:#0000FF;">As </span>Long
   
    <span style="Color:#0000FF;">For </span>lngIndex <span style="Color:#993300;">=</span> <span style="Color:#00FFFF;">1</span> <span style="Color:#0000FF;">To </span>colItems.Count
        lbxListBox.AddItem colItems.Item(lngIndex)
        cboComboBox.AddItem colItems.Item(lngIndex)
    <span style="Color:#0000FF;">Next </span>lngIndex
<span style="Color:#0000FF;">End Sub</span>
 
Ebenso können einzelne Elemente, die nicht aus einer Collection stammen, zur Laufzeit immer wieder hinzugefügt werden.
 
Public Sub AddItem(ByVal strItem As String)
       
    lbxListBox.AddItem strItem
    cboComboBox.AddItem strItem
End Sub


===== Aus einem Bereich einer Excel Tabelle =====
===== Aus einem Bereich einer Excel Tabelle =====


In die 'RowSource'-Eigenschaft kann ein beliebiger Bereich einer Excel-Tabelle als Datenquelle für ein Listen- bzw. Kombinationsfeld eingetragen werden. Hierbei ist zu beachten, dass die Daten für eine Liste aus einer Spalte stammen müssen. Wenn der Bereich eine Zeile darstellt, werden die Daten in eine Zeile übernommen und nicht untereinander dargestellt. <span style="Color:#0000FF;">Public Sub </span>LoadData(<span style="Color:#0000FF;">ByVal </span>strRange <span style="Color:#0000FF;">As </span>String) ' strRange könnte zum Beispiel "A1:A5" oder "A1:E5" enthalten lbxListBox.RowSource <span style="Color:#993300;">= </span>strRange cboComboBox.RowSource <span style="Color:#993300;">= </span>strRange <span style="Color:#0000FF;">End Sub</span> '''Bitte beachten:''' Wenn ein mehrspaltiger Bereich verwendet wird, muss die 'ColumnCount'-Eigenschaft angepasst werden, um die zusätzlichen Spalten darzustellen.
In die 'RowSource'-Eigenschaft kann ein beliebiger Bereich einer Excel-Tabelle als Datenquelle für ein Listen- bzw. Kombinationsfeld eingetragen werden. Hierbei ist zu beachten, dass die Daten für eine Liste aus einer Spalte stammen müssen. Wenn der Bereich eine Zeile darstellt, werden die Daten in eine Zeile übernommen und nicht untereinander dargestellt.
 
<span style="Color:#0000FF;">Public Sub </span>LoadData(<span style="Color:#0000FF;">ByVal </span>strRange <span style="Color:#0000FF;">As </span>String)
    ' strRange könnte zum Beispiel "A1:A5" oder "A1:E5" enthalten
    lbxListBox.RowSource <span style="Color:#993300;">= </span>strRange
    cboComboBox.RowSource <span style="Color:#993300;">= </span>strRange
<span style="Color:#0000FF;">End Sub</span>
 
'''Bitte beachten:''' Wenn ein mehrspaltiger Bereich verwendet wird, muss die 'ColumnCount'-Eigenschaft angepasst werden, um die zusätzlichen Spalten darzustellen.


== Beispiel: Nachbau der Inputbox ==
== Beispiel: Nachbau der Inputbox ==


1. Die UserForm 'frmInputBox' wird dem Layout der Standard-Inputbox nachempfunden. [[Datei:InputBox_01.png]] 2. Die Knöpfe, das Bezeichnungsfeld und das Eingabefeld werden klar benannt und mit den gewünschten Eigenschaften versehen:
1. Die UserForm 'frmInputBox' wird dem Layout der Standard-Inputbox nachempfunden.
 
[[Datei:InputBox_01.png]]
 
2. Die Knöpfe, das Bezeichnungsfeld und das Eingabefeld werden klar benannt und mit den gewünschten Eigenschaften versehen:
* Bezeichnungsfeld: 'lblPrompt'
* Bezeichnungsfeld: 'lblPrompt'
* Eingabefeld (TextBox): 'txtInput'
* Eingabefeld (TextBox): 'txtInput'
* OK-Knopf: 'cmbOK', Eigenschaft 'Default' True
* OK-Knopf: 'cmbOK', Eigenschaft 'Default' True
* Abbrechen-Knopf: 'cmbCancel', Eigenschaft 'Cancel' True 3. Die Ereignisse der UserForm werden ausformuliert. Sie rufen den Code-Editor der UserForm auf, indem Sie sie doppelt anklicken oder 'Ansicht', 'Code anzeigen' wählen. Option Explicit Public CancelWasPressed As Boolean Private Sub cmbOK_Click() Me.Hide End Sub Private Sub cmbCancel_Click() CancelWasPressed = True Me.Hide End Sub Private Sub UserForm_Activate() txtInput.SelStart = 0 txtInput.SelLength = Len(Me.txtName) End Sub Private Sub UserForm_Terminate() CancelWasPressed = True End Sub 4. Eine Prozedur übernimmt Titel, Beschreibung und Vorgabetext in den Dialog. Der Titel wird nur übernommen, wenn er nicht leer ist. Public Sub LoadData(ByVal strPrompt As String, ByVal strTitle As String, ByVal strDefault As String) lblPrompt.Caption = strPrompt If strTitle <> "" Then Me.Caption = strTitle txtInput.Text = strDefault End Sub 5. Eine Funktion gibt anschließend den eingegebenen Text zurück. Public Function ReturnInput() As String ReturnInput = txtInput.Text End Function 6. Die Steuerprozedur ist in diesem Fall eine Funktion, welche den eingegebenen Wert zurückgibt. Wurde die Inputbox abgebrochen, wird, wie im Original, ein Leerstring zurückgegeben. Public Function MyInputBox(ByVal strPrompt As String, ByVal strTitle As String, ByVal strDefault As String) As String Dim myDialog As frmInputBox Set myDialog = New frmInputBox myDialog.LoadData strPrompt, strTitle, strDefault myDialog.Show If myDialog.CancelWasPressed = False Then MyInputBox = myDialog.ReturnInput End If End Function 7. Die fertige Kopie der InputBox: Debug.Print MyInputBox("Bitte etwas eingeben:", "Meine InputBox", "") ' Ergebnis: Test [[Datei:InputBox_02.png]]
* Abbrechen-Knopf: 'cmbCancel', Eigenschaft 'Cancel' True
 
3. Die Ereignisse der UserForm werden ausformuliert. Sie rufen den Code-Editor der UserForm auf, indem Sie sie doppelt anklicken oder 'Ansicht', 'Code anzeigen' wählen.
 
Option Explicit
Public CancelWasPressed As Boolean
Private Sub cmbOK_Click()
 
    Me.Hide
End Sub
Private Sub cmbCancel_Click()
   
    CancelWasPressed = True
    Me.Hide
End Sub
Private Sub UserForm_Activate()
   
    txtInput.SelStart = 0
    txtInput.SelLength = Len(Me.txtName)
End Sub
Private Sub UserForm_Terminate()
 
    CancelWasPressed = True
End Sub
 
4. Eine Prozedur übernimmt Titel, Beschreibung und Vorgabetext in den Dialog. Der Titel wird nur übernommen, wenn er nicht leer ist.
 
Public Sub LoadData(ByVal strPrompt As String, ByVal strTitle As String, ByVal strDefault As String)
   
    lblPrompt.Caption = strPrompt
    If strTitle <> "" Then Me.Caption = strTitle
    txtInput.Text = strDefault
End Sub
 
5. Eine Funktion gibt anschließend den eingegebenen Text zurück.
 
Public Function ReturnInput() As String
   
    ReturnInput = txtInput.Text
End Function
 
6. Die Steuerprozedur ist in diesem Fall eine Funktion, welche den eingegebenen Wert zurückgibt. Wurde die Inputbox abgebrochen, wird, wie im Original, ein Leerstring zurückgegeben.
 
Public Function MyInputBox(ByVal strPrompt As String, ByVal strTitle As String, ByVal strDefault As String) As String
    Dim myDialog As frmInputBox
   
    Set myDialog = New frmInputBox
    myDialog.LoadData strPrompt, strTitle, strDefault
    myDialog.Show
    If myDialog.CancelWasPressed = False Then
        MyInputBox = myDialog.ReturnInput
    End If
End Function
 
7. Die fertige Kopie der InputBox:
 
Debug.Print MyInputBox("Bitte etwas eingeben:", "Meine InputBox", "")         ' Ergebnis: Test
 
[[Datei:InputBox_02.png]]

Aktuelle Version vom 28. Januar 2023, 00:32 Uhr

Zusätzlich zu den eingebauten Dialogen bietet VBA die Möglichkeit, eigene Dialoge zu erstellen. Diese werden 'UserForms' genannt und stellen eine Sonderform von Klassen dar.

Einsatz von Dialogen

Prinzipiell können wir zwischen drei Dialogtypen unterscheiden, die in unserer VBA-Programmierung relevant sind:

  • Mitteilung / einfache Entscheidung: Dem Anwender wird eine Nachricht angezeigt (MessageBox) oder eine Frage gestellt, die eindeutig beantwortet werden kann (Messagebox mit mehrern Knöpfen).
    Beispiele:
MsgBox "Aufgabe erfolgreich erfüllt"
blnContinue = MsgBox("Soll dieser Schritt ausgeführt werden?", vbYesNo) 
  • Eingabe: Der Anwender kann mehrere Daten ändern und den Dialog bestätigen oder den Vorgang abbrechen.
    Beispiele: Eingabe / Bearbeitung von Daten, Einstellungen etc.
  • Komplexe Arbeitsschritte: Ein Dialog (oder mehrere Dialoge) führen durch einen komplexen / über mehrere Schritte verteilten Vorgang.
    Beispiele: Seriendruck in Word

In diesem Kapitel werden wir uns ausschließlich mit Eingabedialogen befassen.

Trennung von Darstellung und Logik

Um den Überblick zu behalten und den Programmfluss optimal zu gestalten, sollte zwischen Darstellung (dem im Dialog Gezeigten) und der Logik (der Programmierung) eine Trennung erfolgen.

Diese Trennung kann anhand des eingebauten Datei-Dialogs veranschaulicht werden:

Public Function BrowseToPath() As String
    Dim dlg As FileDialog
    
    Set dlg = Application.FileDialog(msoFileDialogFolderPicker)
    dlg.Title = "Zielverzeichnis wählen"
    dlg.InitialFileName = "C:\temp\"
    dlg.Show
    If dlg.SelectedItems.Count > 0 Then
        BrowseToPath = dlg.SelectedItems.Item(1)
    End If
End Function
  • Eine Steuerprozedur (die Funktion 'BrowseToPath') fasst alle zur Anzeige und Auswertung des Dialogs benötigten Schritte zusammen.
  • Die Anzeige des Dialogs erfolgt in vier Schritten:

1. Eine Variable wird deklariert und mit dem gewünschten Dialog instanziiert:

    Dim dlg As FileDialog
    
    Set dlg = Application.FileDialog(msoFileDialogFolderPicker)


2. Der Dialog wird für die Anzeige vorbereitet:

    dlg.Title = "Zielverzeichnis wählen"
    dlg.InitialFileName = "C:\temp\"

3. Der Dialog wird angezeigt:

    dlg.Show

4. Die Benutzeringabe wird ausgewertet:

     If dlg.SelectedItems.Count > 0 Then
         BrowseToPath = dlg.SelectedItems.Item(1)
     End If	

Die Steuerprozedur ist demnach größtenteils für die Vorbereitung des Dialogs und die Reaktion auf / die Auswertung der Benutzereingaben beschäftigt. Die Erstellung des Dialogs und dessen Anzeige ergeben sich aus den Hauptaufgaben.

Wenn wir dieses System auf selbst erstellte Eingabedialoge anwenden, ergeben sich folgende Schritte:

Dialog (UserForm)

  Arbeitsschritt Beschreibung / Screenshot / Code
1 Dialog aufbauen
1a Gestaltung des Dialogs (Anlegen und Platzierung der Elemente wie Beschriftungsfelder, Eingabefelder und Knöpfe).
1b Sinnvolle Benennung der Elemente ('frmUserData', 'lblFirstName', 'txtFirstName', 'cmbOK', ...) vornehmen.
2 Ereignisse einsetzen
2a Das Klicken auf den OK-Knopf soll lediglich den Dialog verbergen, damit die Benutzereingaben ausgewertet werden können. Der Befehl 'Me.Hide' gibt die Befehlsgewalt direkt an die Prozedur zurück, welche 'myDialog.Show' aufgerufen hat.
Private Sub cmbOK_Click()
    
    Me.Hide
End Sub
2b Das Klicken auf den Abbrechen-Knopf soll ebenfalls den Dialog verbergen, aber zusätzlich signalisieren, dass der Vorgang abgebrochen wurde. Zusätzlich benötigen wir hierfür eine öffentliche Variable, damit die Steuerprozedur später diesen Wert abrufen kann.
Public CancelWasPressed As Boolean    
 
Private Sub cmbCancel_Click()
     
    CancelWasPressed = True
    Me.Hide 
End Sub

Achtung: Globale Variablen (hier 'Public CancelWasPressed As Boolean') müssen immer vor allen Prozeduren, am besten unter 'Option Explicit', deklariert werden!

2c Um das Beenden mit dem roten 'x' später als Abbruch des Dialogs auswerten zu können, benötigen Sie zusätzlich das UserForm-Ereignis 'Terminate', um auch hier die öffentliche Variable 'CancelWasPressed' auf 'True' zu setzen.
Private Sub UserForm_Terminate()
    
    CancelWasPressed = True
End Sub
3 Dialog füllen und auslesen
3a Eine Prozedur ermöglicht es, dem Dialog die gewünschten Daten und Einstellungen für die Anzeige zu übergeben. Einfache Übernahme von einem Wert:
Public Sub LoadName(ByVal strName As String)
     
    Me.txtName.Text = strName
End Sub

Übernahme von mehreren Werten aus einem benutzerdefinierten Datentyp 'Type':

Public Sub LoadData(ByVal thisData As tpeDialogData)
     
    Me.txtFirstName.Text = thisData.FirstName
    Me.txtLastName.Text = thisData.LastName
    ' ...
End Sub
3b Eine Funktion ermöglicht das Auslesen der vom Benutzer eingegebenen Werte. Einfaches Auslesen eines Wertes:
Public Function ReturnName() As String
     
    ReturnName = Me.txtName.Text
End Function

Auslesen mehrerer Werte mithilfe eines benutzerdefinierten Datentyps 'Type':

Public Function ReturnData() As tpeDialogData)
     
    ReturnDataMe.FirstName = txtFirstName.Text 
    ReturnDataMe.LastName = txtLastName.Text 
    ' ...
End Function

Steuerprozedur

Die Steuerprozedur übernimmt den Aufruf und die Kontrolle über den Dialog. Sie sorgt dafür, dass der Dialog die benötigten Daten erhält, damit er diese anzeigen kann, sie ruft den Dialog auf und sie liest anschließend die eingegebenen Daten aus und verarbeitet diese weiter.

Die Steuerprozedur kann auch eine Funktion sein, welche die Vorgabewerte als Parameter übernimmt und anschließend die Benutzereingabe als Rückgabewert zurück gibt.

  Arbeitsschritt Beschreibung / Screenshot / Code
1 Vorbereitung
1 a Eine Variable zur Erstellung des Dialogs wird deklariert.
     Dim myDialog As frmDialog
1 b Die Variable wird mit 'New' instanziiert.

Das Schlüsselwort 'New' sorgt dafür, dass keine vorherige Instanz des Dialoges verwendet wird. Siehe New.

    Set myDialog = New frmDialog
2 Optional: Die Ausgangsdaten werden an den Dialog übergeben. Hierzu wird die entsprechende Prozedur im Dialog aufgerufen. Dieser Schritt wird nur benötigt, wenn Sie für die Anzeige des Dialogs zusätzliche Informationen benötigen oder Voreinträge machen möchten.
    myDialog.LoadName strName
3 Der Dialog wird angezeigt.
   myDialog.Show
4 a Wenn der Anwender nach der Anzeige mit 'Show' den Dialog schließt, kehrt die Ausführung in die Steuerprozedur zurück. Nun müssen wir klären, ob der Anwender 'Abbrechen' bzw. das rote 'X' oder 'OK' gewählt hat. Wurde der Dialog abgebrochen, soll damit in der Regel der weitere Verlauf der Prozedur ebenfalls abgebrochen werden.
     If myDialog.CancelWasPressed = True Then Exit Sub
4 b Der Dialog wird anschließend ausgewertet, also die Eingabe(n) des Anwenders abgefragt.
    strName = myDialog.ReturnName
Beispiele einer Steuerprozedur
  • Als Sub-Prozedur:
Public Sub ShowDialog() 
     Dim strName As String
     Dim myDialog As frmDialog
     
     Set myDialog = New frmDialog
     myDialog.LoadData
     myDialog.Show
     If myDialog.CancelWasPressed = False Then
         strName = myDialog.ReturnName
         Debug.Print strName
     End If
End Sub
  • Als Funktion:
Public Function EnterName() As String 
     Dim myDialog As frmDialog
     
     Set myDialog = New frmDialog
     myDialog.LoadData
     myDialog.Show
     If myDialog.CancelWasPressed = False Then
         EnterName = myDialog.ReturnName
     End If
End Function

Intuitive Bedienung

Ein sehr wichtiger Aspekt bei der Gestaltung und Programmierung von Dialogen ist selbstverständlich die Bedienbarkeit. Hierzu dienen folgende Vorbereitungen:

OK-Knopf

Folgende Eigenschaft des OK-Knopfes sorgt dafür, dass bei der Betätigung der Eingabetaste (Enter, Return) der Dialog bestätigt wird, indem diese direkt an den OK-Knopf übergeben wird:

Default = True

Abbrechen-Knopf

Folgende Eigenschaft des Abbrechen-Knopfes sorgt dafür, dass bei der Betätigung der Escabe-Taste der Dialog abgebrochen wird, indem diese direkt an den Abbrechen-Knopf übergeben wird:

Cancel = True

Markierung des ersten Eingabefeldes

Um beim Starten des Dialogs das erste Eingabefeld zu markieren (damit der Anwender lediglich durch Eingabe eines Textes den ursprünglichen Wert überschreiben kann, ohne diesen erst löschen zu müssen), können Sie das 'Activate'-Ereignis der UserForm wie folgt erweitern:

Private Sub UserForm_Activate()
   
    txtFirst.SetFocus
    txtFirst.SelStart = 0
    txtFirst.SelLength = Len(Me.txtFirst.Text)
End Sub

Reihenfolge (TabIndex)

Die Reihenfolge beim Ausfüllen von Dialogen (durch Betätigung der Tabulator-Taste) wird mit der 'TabIndex'-Eigenschaft der Elemente bestimmt. Wenn Sie die Eingabefelder in der gewünschten Reihenfolge angelegt haben, müssen Sie diese in der Regel nicht nachbearbeiten. Wenn Sie jedoch nachträglich weitere Felder hinzufügen oder die Reihenfolge ändern, sollten Sie den Dialog daraufhin prüfen und die 'TabIndex'-Eigenschaft entsprechend anpassen.

Bitte beachten: Der erste TabIndex beträgt 0, alle weiteren werden um einen Index erhöht. Wenn Sie einen schon vorhandenen Index neu vergeben, erhält das Element mit dem doppelten Index einen neuen Index.

Bitte beachten: Der 'TabIndex' wird nicht beachtet, wenn die Eigenschaft 'TabStop' nicht 'True' ist!

Tipp: Die 'SetDefaultTabOrder'-Methode des UserForms weist allen Elementen des Dialogs eine neue Reihenfolge zu, die von links nach rechts und oben nach unten erfolgt.

Private Sub UserForm_Activate()
    
    Me.SetDefaultTabOrder
End Sub

Eingabe zulassen / unterdrücken

Wenn Sie ausschließlich die Eingabe von vorgegebenen Zeichen in ein Eingabefeld (TextBox) zulassen möchten (zum Beispiel zur Eingabe einer Telefonnummer), können Sie das 'KeyPress'-Ereignis wie folgt einsetzen:

Private Sub txtTextbox_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger)

    ' Eingabe von nur diesen Zeichen zulassen
    If Not Chr(KeyAscii) Like "[0-9./+ -]" Then
        Beep             ' Gibt einen Warnton aus
        KeyAscii = 0
    End If
End Sub

Wenn Sie die Eingabe von bestimmten Zeichen unterdrücken möchten, können Sie wie folgt vorgehen:

Private Sub txtValue_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger)
    
    ' Eingabe von diesen Zeichen unterdrücken
    If Chr(KeyAscii) Like "[.:-]" Then
        Beep             ' Gibt einen Warnton aus
        KeyAscii = 0
    End If
End Sub

Elemente einer UserForm (Controls)

Listenfeld und Kombinationsfeld (ListBox und Combobox)

Das Listenfeld und das Kombinationsfeld sind sehr stark miteinander verwandt, denn beide stellen Datenreihen als Liste bzw. Tabelle dar. Der größte Unterschied ist die Darstellung: Das Listenfeld ist ein immer aufgeklapptes Kombinationsfeld, das Kombinationsfeld ein Listenfeld, bei dem nur der erste (bzw. gewählte) Eintrag sichtbar ist -- die weiteren Einträge können bei Bedarf sichtbar gemacht werden.

Listenfeld und Kombinationsfeld mit Daten füllen

Hierfür stehen insgesamt zwei (bei Excel drei) Wege zur Verfügung:

Aus einem Array

Wenn die Daten in Form eines Arrays vorliegen, können sie direkt in die 'List'-Eigenschaft übernommen werden:

Public Sub LoadData(ByRef strItems() As String)

    lbxListBox.List = strItems
    cboComboBox.List = strItems
End Sub

Bitte beachten: Wenn ein mehrspaltiges Array übergeben wird, muss die 'ColumnCount'-Eigenschaft verwendet werden, um die zusätzlichen Spalten darzustellen.

Einzelne Elemente hinzufügen

Wenn die Daten als Collection vorliegen, können sie einzeln per 'AddItem' hinzugefügt werden:

Public Sub LoadData(ByVal colItems As Collection)
    Dim lngIndex As Long
    
    For lngIndex = 1 To colItems.Count
        lbxListBox.AddItem colItems.Item(lngIndex)
        cboComboBox.AddItem colItems.Item(lngIndex)
    Next lngIndex
End Sub

Ebenso können einzelne Elemente, die nicht aus einer Collection stammen, zur Laufzeit immer wieder hinzugefügt werden.

Public Sub AddItem(ByVal strItem As String)
       
    lbxListBox.AddItem strItem
    cboComboBox.AddItem strItem
End Sub
Aus einem Bereich einer Excel Tabelle

In die 'RowSource'-Eigenschaft kann ein beliebiger Bereich einer Excel-Tabelle als Datenquelle für ein Listen- bzw. Kombinationsfeld eingetragen werden. Hierbei ist zu beachten, dass die Daten für eine Liste aus einer Spalte stammen müssen. Wenn der Bereich eine Zeile darstellt, werden die Daten in eine Zeile übernommen und nicht untereinander dargestellt.

Public Sub LoadData(ByVal strRange As String)
    ' strRange könnte zum Beispiel "A1:A5" oder "A1:E5" enthalten

    lbxListBox.RowSource = strRange
    cboComboBox.RowSource = strRange
End Sub

Bitte beachten: Wenn ein mehrspaltiger Bereich verwendet wird, muss die 'ColumnCount'-Eigenschaft angepasst werden, um die zusätzlichen Spalten darzustellen.

Beispiel: Nachbau der Inputbox

1. Die UserForm 'frmInputBox' wird dem Layout der Standard-Inputbox nachempfunden.

InputBox 01.png

2. Die Knöpfe, das Bezeichnungsfeld und das Eingabefeld werden klar benannt und mit den gewünschten Eigenschaften versehen:

  • Bezeichnungsfeld: 'lblPrompt'
  • Eingabefeld (TextBox): 'txtInput'
  • OK-Knopf: 'cmbOK', Eigenschaft 'Default' True
  • Abbrechen-Knopf: 'cmbCancel', Eigenschaft 'Cancel' True

3. Die Ereignisse der UserForm werden ausformuliert. Sie rufen den Code-Editor der UserForm auf, indem Sie sie doppelt anklicken oder 'Ansicht', 'Code anzeigen' wählen.

Option Explicit

Public CancelWasPressed As Boolean

Private Sub cmbOK_Click()
  
    Me.Hide
End Sub


Private Sub cmbCancel_Click()
   
    CancelWasPressed = True
    Me.Hide
End Sub


Private Sub UserForm_Activate()
    
    txtInput.SelStart = 0
    txtInput.SelLength = Len(Me.txtName)
End Sub


Private Sub UserForm_Terminate()
  
    CancelWasPressed = True
End Sub

4. Eine Prozedur übernimmt Titel, Beschreibung und Vorgabetext in den Dialog. Der Titel wird nur übernommen, wenn er nicht leer ist.

Public Sub LoadData(ByVal strPrompt As String, ByVal strTitle As String, ByVal strDefault As String)
    
    lblPrompt.Caption = strPrompt
    If strTitle <> "" Then Me.Caption = strTitle
    txtInput.Text = strDefault
End Sub

5. Eine Funktion gibt anschließend den eingegebenen Text zurück.

Public Function ReturnInput() As String
   
    ReturnInput = txtInput.Text
End Function

6. Die Steuerprozedur ist in diesem Fall eine Funktion, welche den eingegebenen Wert zurückgibt. Wurde die Inputbox abgebrochen, wird, wie im Original, ein Leerstring zurückgegeben.

Public Function MyInputBox(ByVal strPrompt As String, ByVal strTitle As String, ByVal strDefault As String) As String
    Dim myDialog As frmInputBox
    
    Set myDialog = New frmInputBox
    myDialog.LoadData strPrompt, strTitle, strDefault
    myDialog.Show
    If myDialog.CancelWasPressed = False Then
        MyInputBox = myDialog.ReturnInput
    End If
End Function

7. Die fertige Kopie der InputBox:

Debug.Print MyInputBox("Bitte etwas eingeben:", "Meine InputBox", "")         ' Ergebnis: Test

InputBox 02.png