UserForms: Unterschied zwischen den Versionen
Pwania (Diskussion | Beiträge) (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…“) |
Pwania (Diskussion | Beiträge) 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;"> | 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 | * 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;" | | ! style="text-align:left;" | | ||
! 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. | |||
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;" | | ! style="text-align:left;" | | ||
! 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 a | | 1 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 b | | 1 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 a | | 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. | | 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 b | | 4 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 | |||
|} | |} | ||
* Als Sub-Prozedur: <span style="Color:#0000FF;"> | ;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 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.
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