Dialoge: Unterschied zwischen den Versionen

Aus VBA-wiki
Zur Navigation springen Zur Suche springen
(Die Seite wurde neu angelegt: „== Dialoge optimal konzipieren == Dialoge ermöglichen den Austausch mit dem Anwender. Dieser Austausch kann einseitig sein, wie ein Hinweis, der nur bestäti…“)
 
Keine Bearbeitungszusammenfassung
Zeile 1: Zeile 1:
== Dialoge optimal konzipieren ==
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.


Dialoge ermöglichen den Austausch mit dem Anwender. Dieser Austausch kann einseitig sein, wie ein Hinweis, der nur bestätigt werden kann, oder beidseitig, wie ein Eingabedialog. Um das Arbeiten und insbesondere das Nachbessern von Dialogen so übersichtlich wie möglich zu gestalten, bietet es sich an, einen einheitlichen Handlungsstrang zu verfolgen, der sich aus folgenden Schritten zusammensetzt:
== Trennung von Darstellung und Logik ==
# Eine Steuerprozedur
 
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>
* 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:
 
=== Dialog (UserForm) ===
 
{| class="wikitable"
! style="text-align:left;" | &nbsp;
! style="text-align:left;" | Arbeitsschritt
! style="text-align:left;" | Beschreibung / Screenshot / Code
|- style="vertical-align:top;"
| 1
| '''Dialog aufbauen''' |
|- style="vertical-align:top;"
| 1a
| Gestaltung des Dialogs (Anlegen und Platzierung der Elemente wie Beschriftungsfelder, Eingabefelder und Knöpfe). |
|- style="vertical-align:top;"
| 1b
| Sinnvolle Benennung der Elemente ('frmUserData', 'lblFirstName', 'txtFirstName', 'cmbOK', ...) vornehmen. |
|- style="vertical-align:top;"
| 2
| '''Ereignisse einsetzen''' |
|- style="vertical-align:top;"
| 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.
| <span style="Color:#0000FF;">Private Sub </span>cmbOK_Click() Me.Hide <span style="Color:#0000FF;">End Sub</span>
|- style="vertical-align:top;"
| 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.
| <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;"
| 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.
| <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;"
| 3
| '''Dialog füllen und auslesen''' |
|- style="vertical-align:top;"
| 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: <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;"
| 3b
| 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>
|}
 
 
=== 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.
{| class="wikitable"
! style="text-align:left;" | &nbsp;
! style="text-align:left;" | Arbeitsschritt
! style="text-align:left;" | Beschreibung / Screenshot / Code
|- style="vertical-align:top;"
| 1
| '''Vorbereitung''' |
|- style="vertical-align:top;"
| 1&nbsp;a
| Eine Variable zur Erstellung des Dialogs wird deklariert.
| <span style="Color:#0000FF;">Dim </span>myDialog <span style="Color:#0000FF;">As </span>frmDialog
|- style="vertical-align:top;"
| 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]].
| <span style="Color:#0000FF;">Set </span>myDialog <span style="Color:#993300;">= </span>New frmDialog
|- style="vertical-align:top;"
| 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
|- style="vertical-align:top;"
| 3
| Der Dialog wird angezeigt.
| myDialog.Show
|- style="vertical-align:top;"
| 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.
| <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;"
| 4&nbsp;b
| Der Dialog wird anschließend ausgewertet, also die Eingabe(n) des Anwenders abgefragt.
| 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>
* 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 ==
 
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. <span style="Color:#0000FF;">Private Sub </span>UserForm_Activate() Me.SetDefaultTabOrder <span style="Color:#0000FF;">End Sub</span>
 
=== 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: <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 =====
 
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 =====
 
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 ==
 
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'
* 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 [[Datei:InputBox_02.png]]

Version vom 23. November 2017, 10:48 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.

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: Private 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 Dialoge anwenden, ergeben sich folgende Schritte:

Dialog (UserForm)

  Arbeitsschritt Beschreibung / Screenshot / Code
1
1a
1b
2
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
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
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: Private 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