Wie kann ich Daten aus Zellen in eine Userform-Listbox einlesen lassen, die zugehörigen Angaben beim Klick auf die Listbox in Textboxen anzeigen lassen und �nderungen in der Userform in die Zellen schreiben lassen?
Bei der Arbeit mit Userforms gibt es immer verschiedene Wege, die zu einem Ziel führen. Die Kunst ist immer, Techniken/Konzeptionen zu wählen, die den eigenen Anforderungen am besten entsprechen; die am sichersten sind, möglichst kurze Laufzeiten aufweisen und Ressourcen am besten schonen. Darum soll es hier aber nicht gehen. An dieser Stelle stehen grundsätzliche Möglichkeiten im Mittelpunkt, die aufzeigen, wie die Aufgabenstellung prinzipiell gelöst werden kann. Auf Fehlerbehandlungen, Ergonomie und Schönheit wird hier deshalb verzichtet.
Für das Beispiel wird die abgebildete kleine Tabelle auf dem Blatt Daten verwendet; funktionieren soll dann die Userform1 mit den folgenden grundsätzlichen Elementen:
- Listbox1 (das wird die Obstliste)
- TextBox1
- TextBox2
- TextBox3
- TextBox4
- CommandButton1 (Neu)
- CommandButton2 (SchlieÃ?en)
Tipp: Auch wenn wir hier die Standardbezeichnungen der Elemente verwenden - übersichtlicher ist es, wenn Sie jedem Element eine aussagekräftige Eigenschaft bei Name vergeben. Commandbutton1 könnte so zum Beispiel cmdNeu genannt werden.
Nun müssen wir uns schon entscheiden: Der Code kann in ein allgemeines Modul (Modul1, Modul2, �) oder in diesem Fall in das Klassenmodul der Userform. Nehmen wir ein allgemeines Modul, muss im Code immer die gesamte Userform angesprochen werden, denn allgemeine Module stehen für die gesamte (in diesem Fall) Mappe - wenn mit mehreren Userforms gearbeitet würde, müsste der Code dort wissen, welche Userform angesprochen werden soll. Wir entscheiden uns hier für das Klassenmodul der Userform, das konkret dieser Userform zugeordnet ist.
Klassenmodul der Userform: Basis für den Code
In das Modul der Userform gelangt man am einfachsten und schnellsten, indem man auf das Element, für das der Code erstellt werden soll, doppelklickt. Wir wollen zuerst einmal dafür sorgen, dass die Userform per Klick auf Schlie�en geschlossen werden kann. Dazu also ein Doppelklick auf den Button (Commandbutton2 war das). Wir gelangen in das Klassenmodul, haben schon den vorbereiteten Code, der für das Klicken auf den Button zuständig ist und tragen dort einfach Unload Me ein:
Private Sub CommandButton2_Click()
Unload Me
End Sub
Mit F5 kann das auch gleich getestet werden Userform aufrufen und Button anklicken.
Einlesen der Daten aus der Tabelle
Der nächste Schritt ist das Einlesen der Daten von der Tabelle in die Listbox. Dies soll geschehen, wenn die Userform aufgerufen, also geladen wird.
Dazu wählen wir - wenn es noch nicht eingestellt ist - links oben das Element, die Userform. Rechts wählen wir das Ereignis, also wann es geschehen soll. Das ist hier Initlialize.
Wenn wir das gewählt haben, steht auch schon der Code dafür da, den wir vervollständigen. Im ersten Beispiel wählen wir die gebundene Form - die Daten erscheinen in der Listbox genau so, wie sie in der Tabelle stehen:
Private Sub UserForm_Initialize()
ListBox1.RowSource = "Daten!B2:B10"
End Sub
Manchmal kann es jedoch notwendig sein, die Daten ungebunden in die Liste einzutragen, wenn zum Beispiel Einträge ergänzt werden sollen. Im folgenden Beispiel wird dies gezeigt, indem die Daten aus Spalte A vorangestellt werden. Verwendet werden hier die Daten von Zeile 2 bis zur letzten in Spalte 2 ausgefüllten Zelle:
Private Sub UserForm_Initialize()
'ListBox1.RowSource = "Daten!B2:B10"
Dim lngZ As LongPtr
With Sheets("Daten")
For lngZ = 2 To .Cells(Rows.Count, 2).End(xlUp).Row
ListBox1.AddItem .Cells(lngZ, 1) & " - " & .Cells(lngZ, 2)
Next
End With
End Sub
Im zweiten Beispiel sind die Daten ungebunden in der Liste - ändern sich die Daten in der Tabelle, bleibt die Listbox so, wie sie erstellt wurde.
Details zu gewähltem Listeneintrag anzeigen
Nun können wir unsere Einträge in der Liste anklicken, aber es passiert natürlich noch nichts. Dass rechts in den Textboxen die Details zum angeklickten Eintrag erscheinen, müssen wir erst eingeben. Es soll etwas beim Anklicken der Listbox passieren - also doppelklicken wir im Editor doppelt auf die Listbox und haben den Rahmen für den Code:
Private Sub ListBox1_Click()
End Sub
Zunächst einmal ist wichtig, aus welcher Zeile des Tabellenblattes die Daten kommen sollen, wenn wir auf einen Eintrag in der Listbox klicken.
Dazu nutzen wir die Listindex-Eigenschaft der Listbox. Wenn wir in einer Listbox einen Eintrag auswählen, hat der immer einen Listindex, beginnend mit 0. Ist kein Eintrag ausgewählt, ist der Listindex -1.
Wenn wir also den ersten Eintrag anklicken, sollen die Daten aus der Zeile 2 erscheinen, beim zweiten Eintrag die Daten aus Zeile 3 usw. Wir addieren also zum Listindex einfach 2 und verwenden für die einzelne Textbox den jeweiligen Eintrag aus den Spalten 1 bis 4. Das kann so aussehen:
Dim intIndex As Integer
intIndex = ListBox1.ListIndex
With Sheets("Daten")
TextBox1.Text = .Cells(intIndex + 2, 1)
TextBox2.Text = .Cells(intIndex + 2, 2)
TextBox3.Text = .Cells(intIndex + 2, 3)
TextBox4.Text = .Cells(intIndex + 2, 4)
End With
Nun kann allerdings der Fall eintreten, dass mal kein Eintrag gewählt ist. Dann sollen die Textboxen leer sein. Dafür verwenden wir hier eine kleine Schleife - da wir das später nochmal benötigen, lagern wir das in eine separate Sub() aus, die wir dann einfach aufrufen:
Sub TextBoxenLeer()
Dim ctrControl As Control
For Each ctrControl In Me.Controls
If ctrControl.Name Like "TextBox*" Then ctrControl.Text = ""
Next
End Sub
Damit vervollständigen wir den Code der Listbox, so dass er so aussieht und wir es mit z. B. F5 testen können:
Private Sub ListBox1_Click()
Dim intIndex As Integer
intIndex = ListBox1.ListIndex
If intIndex >= 0 Then
With Sheets("Daten")
TextBox1.Text = .Cells(intIndex + 2, 1)
TextBox2.Text = .Cells(intIndex + 2, 2)
TextBox3.Text = .Cells(intIndex + 2, 3)
TextBox4.Text = .Cells(intIndex + 2, 4)
End With
Else
TextBoxenLeer
End If
End Sub
�nderungen aus der Userform in die Tabelle übernehmen
Nun sollen �nderungen, die in den Textboxen vorgenommen werden, auch in die Tabelle übernommen werden. Hierbei ist es besonders wichtig, wie man vorgeht - bei vier Textboxen ist das sicher kein Problem, aber bei grö�eren Datenmasken kann bei einer unzweckmä�igen Technik schon viel überflüssiger Code entstehen. Für den Anfang sei hier jedoch nur auf das Erstellen einer separaten Klasse verwiesen oder auch auf das Verwenden eines Frames und das komplette �bernehmen mit einem Klick. Der Einfachheit halber weisen wir das �bernehmen hier den Textboxen direkt zu.
Damit wir nicht bei jeder Textbox überflüssigen Code wiederholen müssen, bereiten wir eine Sub() vor, die wir dann bei den Textboxen nur noch aufrufen. Die Sub() macht nichts anderes, als einen Wert in die Zelle lngZeile, lngSpalte zu schreiben:
Sub DatenInTabelle(ByVal lngZeile As LongPtr, ByVal lngSpalte As LongPtr, varWert)
If lngZeile >= 2 Then Sheets("Daten").Cells(lngZeile, lngSpalte) = varWert
End Sub
Damit das bei �nderungen in den Textboxen geschieht, müssen wir dazu noch den Code erstellen - auch hier wieder durch Doppelklick auf die einzelnen Textboxen. Dadurch erhalten wir die Code-Rahmen für die Boxen und fügen nur noch den Verweis auf die Sub ein, die wir gerade erstellt haben. Das sieht dann so aus:
Private Sub TextBox1_Change()
DatenInTabelle ListBox1.ListIndex + 2, 1, TextBox1.Text
End Sub
Private Sub TextBox2_Change()
DatenInTabelle ListBox1.ListIndex + 2, 2, TextBox2.Text
End Sub
Private Sub TextBox3_Change()
DatenInTabelle ListBox1.ListIndex + 2, 3, TextBox3.Text
End Sub
Private Sub TextBox4_Change()
DatenInTabelle ListBox1.ListIndex + 2, 4, TextBox4.Text
End Sub
Wir sehen, dass auch hier für die Angabe der Zeile der Listindex der Listbox verwendet wird. Da der beim ersten Eintrag 0 ist, die Tabelle aber bei Zeile 2 beginnt, müssen wir hier noch die 2 addieren. Für den Fall, dass mal kein Eintrag in der Listbox gewählt ist (entspricht Listindex = -1), haben wir in Sub DatenInTabelle() noch die Abfrage If lngZeile >= 2 Then .
Damit sollte eine �nderung bei einem gewählten Eintrag übernommen werden. Da es hier um das Prinzip geht, lassen wir hier das Aktualisieren der Listeneinträge bei �nderungen der Spalten 1 und 2 au�en vor. Erwähnt sei nur, dass dies einfach mit ListBox1.List(ListBox1.ListIndex) = möglich ist.
Neuer Eintrag
Fehlt eigentlich nur noch eins: Wie fügt man einen neuen Eintrag hinzu?
In diesem Fall machen wir es ganz einfach: Wir lassen in die erste leere Zelle in Spalte 2 (B) und in die Listbox einen Eintrag vornehmen und diesen in der Listbox auswählen. Der Rest funktioniert dann bereits.
Private Sub CommandButton1_Click()
Dim lngZ As LongPtr
With Sheets("Daten")
lngZ = .Cells(Rows.Count, 2).End(xlUp).Row + 1
.Cells(lngZ, 2) = "Neuer Eintrag"
End With
ListBox1.AddItem "Neuer Eintrag"
ListBox1.ListIndex = ListBox1.ListCount - 1
End Sub
Der Nachteil ist, dass die Liste dann diesen Eintrag behält, aber das lässt sich leicht beheben. Am einfachsten schreibt man den Code aus Einlesen der Daten aus der Tabelle in eine separate Sub und lässt die beim Aufruf der Userform und beim Erstellen eines neuen Eintrags ausführen.
Viel Erfolg!