Anzeige

VBA
Programmierer
gesucht?
 
Anzeige
VBA Programmierer gesucht?
 

VBA Tutorials

Eine einfache Eingabemaske für eine Excel® Tabelle erstellen Version 2 - die ausführlichere Variante!

Da es zu meinem vorherigen Tutorial sehr viel positives Feedback gab, habe ich mich entschlossen eine Version 2 des Tutorials aufzusetzen. In dieser Version möchte ich allerdings mehr auf die eigentliche Programmierung, sprich den VBA Quelltext selbst, eingehen. Wie man eine Eingabemaske entsprechend im VBA-Editor erstellt, ist im vorherigen Tutorial zu sehen.

Dieses Tutorial ist etwas anspruchsvoller als das vorherige. Ich versuche Ihnen jedoch so viel Quelltext-Erläuterungen wie möglich an die Hand zu geben, so dass Sie den Beispiel-Code auch möglichst vollständig verstehen. Für Einsteiger und nicht so fortgeschrittene Benutzer empfehle ich einen Blick in die VBA Grundlagen, denn alles kann ich in einem Tutorial nicht ausführlich erläutern, dafür ist die Materie zu umfangreich. Aber auch zu den Grundlagen von VBA gibt es im Netz und hier auf Online-VBA.de kostenloses Einsteiger-Material.

Hinweis: Für dieses Tutorial wurde Microsoft® Office Professional Version 2016 verwendet. Als Betriebssystem wurde Windows® 10 verwendet. Wenn Sie eine andere Version verwenden, kann es Unterschiede im Erscheinungsbild geben! Verwenden Sie Microsoft® Office für Mac®? Hier gibt es einige weitere Unterschiede, welche ich in diesem Tutorial aber nicht weiter ansprechen möchte.

Ich habe für alle das unten folgende Beispiel als fertige Datei zum Download bereitgestellt. Sie finden den Download-Link am Ende dieses Tutorials.

Die Ausgangslage und Zielsetzung

Unser Ziel ist eine flexiblere Programmierung für die einfache Adressliste aus dem ersten Tutorial zu bauen.
Dabei möchte ich tiefer auf die Programmierung eingehen und zusätzlich noch etwas mehr Parametrisierung ins Spiel bringen.
Trotzdem: In diesem Tutorial geht es lediglich um Grundlagenwissen. Komplizierte Eingabeprüfungen und Fehlerbehandlungsroutinen werde ich auch hier nicht ansprechen.

Zusätzliche Anforderungen im Vergleich zum ersten Tutorial:

  • Anzeige von mehreren Spalten in der ListBox
  • Verarbeitung ohne ID-Spalte (so dass ein Name mehrfach vorkommen kann)
  • Einfache Erweiterbarkeit für neue Tabellenspalten
  • Eine Sicherheitsabfrage vor dem Löschen
  • Leerzeilen in der Tabelle ignorieren bzw. für neue Einträge nutzen

Schauen wir uns die Ausgangslage bzw. die Tabelle aus dem ersten Tutorial noch einmal kurz an.

  A B C D E F G H I
 1  Name Telefon E-Mail Adresse PLZ Ort                                 
 2  Marc 12345 info@wershovenonline.de Musterstrasse 16 12345 Musterhausen      
 3  Anika 54321 keine vorhanden Beispielweg 2 54321 Musterort      
 4  Max Mustermann 33445 max@mustermann.de Muster-Haupt-Str. 3 22334 Mustermetropole      
 5                   
 6                   

Die Eingabemaske

Wir verwenden die gleiche Eingabemaske wie im ersten Tutorial.
Nur die Liste (ListBox1) können Sie etwas breiter gestalten, da wir mehrere Spalten anzeigen möchten.

Abbildung 1 - Verbreitern der Liste auf der Eingabemaske


Die Funktionalitäten der Eingabemaske erstellen (Version 2)

Um unserer Benutzeroberfläche "das Leben einzuhauchen" Doppel-Klicken Sie bitte auf die "Beenden"-Schaltfläche, unserem CommandButton_4 auf unserer UserForm1. Der Quellcode Editor wird geöffnet und Sie sehen schon etwas Quelltext bzw. den alten Quelltext aus dem ertsten Tutorial. Löschen Sie den gesamten Quelltext vollständig und fügen Sie den folgenden neuen Quelltext der Version 2 vollständig ein.

Wie der Quelltext genau funktioniert, erfahren Sie direkt im Folge-Kapitel, im Anschluss an den Quelltext.

Der Quelltext...

Option Explicit
Option Compare Text
' ************************************************************************************************
' Autor/en: http://www.online-vba.de - Marc Wershoven
' Verwendung der Quelltexte auf eigene Gefahr!
' Es gelten die Nutzungsbedingungen von www.online-vba.de!
' Original-Quelltext: www.online-vba.de/vba_tutorialuserform2.php
' ************************************************************************************************

' ************************************************************************************************
' KONSTANTEN / PARAMETRISIERUNG
' ************************************************************************************************

'Wie viele TextBoxen sind auf der UserForm platziert?
Private Const iCONST_ANZAHL_EINGABEFELDER As Integer = 6

'In welcher Zeile starten die Eingaben?
Private Const lCONST_STARTZEILENNUMMER_DER_TABELLE As Long = 2


' ************************************************************************************************
' EREIGNISROUTINEN DER USERFORM
' ************************************************************************************************

'Neuer Eintrag Schaltfläche Ereignisroutine
Private Sub CommandButton1_Click()
     Call EINTRAG_ANLEGEN 'Aufruf der entsprechenden Verarbeitungsroutine
End Sub

'Löschen Schaltfläche Ereignisroutine
Private Sub CommandButton2_Click()
     Call EINTRAG_LOESCHEN 'Aufruf der entsprechenden Verarbeitungsroutine
End Sub

'Speichern Schaltfläche Ereignisroutine
Private Sub CommandButton3_Click()
     Call EINTRAG_SPEICHERN 'Aufruf der entsprechenden Verarbeitungsroutine
End Sub

'Beenden Schaltfläche Ereignisroutine
Private Sub CommandButton4_Click()
     Unload Me
End Sub

'Klick auf die ListBox Ereignisroutine
Private Sub ListBox1_Click()
     Call EINTRAG_LADEN_UND_ANZEIGEN 'Aufruf der entsprechenden Verarbeitungsroutine
End Sub

'Diese Ereignisroutine wird beim Anzeigen der UserForm ausgeführt
Private Sub UserForm_Activate()
     If ListBox1.ListCount > 0 Then ListBox1.ListIndex = 0 '1. Eintrag selektieren
End Sub

'Startroutine, wird ausgeführt bevor die Eingabemaske angezeigt wird
Private Sub UserForm_Initialize()
     Call LISTE_LADEN_UND_INITIALISIEREN 'Aufruf der entsprechenden Verarbeitungsroutine
End Sub


' ************************************************************************************************
' VERARBEITUNGSROUTINEN
' ************************************************************************************************

'Diese Routine wird aufgerufen um die Liste (ListBox1) zu leeren, einzustellen und neu zu füllen
Private Sub LISTE_LADEN_UND_INITIALISIEREN()
   Dim lZeile As Long
   Dim lZeileMaximum As Long
   Dim i As Integer
  
     'Alle TextBoxen leer machen
     For i = 1 To iCONST_ANZAHL_EINGABEFELDER
         Me.Controls("TextBox" & i) = ""
     Next i

     ListBox1.Clear 'Liste leeren
    
     '4 Spalten einrichten
     'Spalte 1: Zeilennummer des Datensatzes
     'Spalte 2: Name (Spalte A)
     'Spalte 3: Telefon (Spalte B)
     'Spalte 4: E-Mail (Spalte C)
     ListBox1.ColumnCount = 4
    
     'Spaltenbreiten der Liste anpassen (0=ausblenden, nichts=automatisch)
     '"<Breite Spalte 1>;<Breite Spalte 2>;<Breite Spalte 3>;<Breite Spalte 4>"
     ListBox1.ColumnWidths = "0;;;"
     'Feste Breiten: ListBox1.ColumnWidths = "0;100;100;100"
    
     'Um eine Schleife für alle Datensätze zu erhalten, benötigen wir die letzte verwendete Zeile
     lZeileMaximum = Tabelle1.UsedRange.Rows.Count 'Benutzer Bereich auslesen
    
     For lZeile = lCONST_STARTZEILENNUMMER_DER_TABELLE To lZeileMaximum
        
         'Nur wenn die Zeile benutzt / nicht leer ist, zeigen wir etwas an:
         If IST_ZEILE_LEER(lZeile) = False Then
            
             'Spalte 1 der Liste mit der Zeilennummer füllen
             ListBox1.AddItem lZeile
            
             'Spalten 2 bis 4 der Liste füllen
             ListBox1.List(ListBox1.ListCount - 1, 1) = CStr(Tabelle1.Cells(lZeile, 1).Text)
             ListBox1.List(ListBox1.ListCount - 1, 2) = CStr(Tabelle1.Cells(lZeile, 2).Text)
             ListBox1.List(ListBox1.ListCount - 1, 3) = CStr(Tabelle1.Cells(lZeile, 3).Text)
        
         End If
        
     Next lZeile
    
End Sub

Private Sub EINTRAG_LADEN_UND_ANZEIGEN()
   Dim lZeile As Long
   Dim i As Integer
    
     'Eingabefelder resetten
     For i = 1 To iCONST_ANZAHL_EINGABEFELDER
         Me.Controls("TextBox" & i) = ""
     Next i
    
     'Nur wenn ein Eintrag selektiert/markiert ist
     If ListBox1.ListIndex >= 0 Then
           
         'Die Zeilennummer des Datensatzes steht in der ersten ausgeblendeten Spalte der Liste,
         'somit können wir direkt zugreifen.
         lZeile = ListBox1.List(ListBox1.ListIndex, 0)
        
         For i = 1 To iCONST_ANZAHL_EINGABEFELDER
             Me.Controls("TextBox" & i) = CStr(Tabelle1.Cells(lZeile, i).Text)
         Next i
            
     End If
    
End Sub

Private Sub EINTRAG_SPEICHERN()
  Dim lZeile As Long
  Dim i As Integer
 
     'Wenn kein Datensatz in der ListBox markiert wurde, wird die Routine beendet
     If ListBox1.ListIndex = -1 Then Exit Sub
   
     'Zum Speichern benötigen wir die Zeilennummer des ausgewählten Datensatzes
     lZeile = ListBox1.List(ListBox1.ListIndex, 0)
    
     For i = 1 To iCONST_ANZAHL_EINGABEFELDER
         Tabelle1.Cells(lZeile, i) = Me.Controls("TextBox" & i)
     Next i
    
     'Der Benutzer könnte die angezeigten Werte in der Liste geändert haben,
     'daher aktualisieren wir den ausgewählten Eintrag entsprechend.
     ListBox1.List(ListBox1.ListIndex, 1) = TextBox1
     ListBox1.List(ListBox1.ListIndex, 2) = TextBox2
     ListBox1.List(ListBox1.ListIndex, 3) = TextBox3
    
End Sub

Private Sub EINTRAG_LOESCHEN()
  Dim lZeile As Long
  
     'Wenn kein Datensatz in der ListBox markiert wurde, wird die Routine beendet
     If ListBox1.ListIndex = -1 Then Exit Sub
  
     'Beim Löschen fragen wir zuerst den Benutzer noch einmal sicherheitshalber:
     If MsgBox("Sie möchten den markierten Datensatz wirklich löschen?", _
               vbQuestion + vbYesNo, "Sicherheitsabfrage!") = vbYes Then
  
         'Nur wenn er mit <JA> antwortet, löschen wir auch!
  
         'Zum Löschen benötigen wir die Zeilennummer des ausgewählten Datensatzes
         lZeile = ListBox1.List(ListBox1.ListIndex, 0)
        
         'Die ganze Zeile wird nun gelöscht
         Tabelle1.Rows(CStr(lZeile & ":" & lZeile)).Delete
        
         'Und den Eintrag in der Liste müssen wir auch noch entfernen
         ListBox1.RemoveItem ListBox1.ListIndex
    
     End If
    
End Sub

Private Sub EINTRAG_ANLEGEN()
  Dim lZeile As Long
    
     lZeile = lCONST_STARTZEILENNUMMER_DER_TABELLE
     'Schleife bis eine leere ungebrauchte Zeile gefunden wird
     Do While IST_ZEILE_LEER(lZeile) = False
         lZeile = lZeile + 1 'Nächste Zeile bearbeiten
     Loop
    
     'Nach Durchlauf dieser Schleife steht lZeile in der ersten leeren Zeile von Tabelle1
     Tabelle1.Cells(lZeile, 1) = CStr("Neuer Eintrag Zeile " & lZeile)
    
     'Und neuen Eintrag in die UserForm eintragen
     ListBox1.AddItem lZeile
     ListBox1.List(ListBox1.ListCount - 1, 1) = CStr("Neuer Eintrag Zeile " & lZeile)
     ListBox1.List(ListBox1.ListCount - 1, 2) = ""
     ListBox1.List(ListBox1.ListCount - 1, 3) = ""
    
     'Den neuen Eintrag markieren mit Hilfe des ListIndex
     ListBox1.ListIndex = ListBox1.ListCount - 1
     'Durch das Click Ereignis der ListBox werden die Daten automatisch geladen
    
     'Und dem Benutzer direkt noch den Cursor in das erste Eingabefeld stellen und alles vorselektieren,
     'so kann der Benutzer direkt loslegen mit der Dateneingabe.
     TextBox1.SetFocus
     TextBox1.SelStart = 0
     TextBox1.SelLength = Len(TextBox1)
    
End Sub


' ************************************************************************************************
' HILFSFUNKTIONEN
' ************************************************************************************************

'Ermittelt, ob eine Zeile in Benutzung ist...
Private Function IST_ZEILE_LEER(ByVal lZeile As Long) As Boolean
   Dim i As Long
   Dim sTemp As String
  
     'Hilfsvariable initialisieren
     sTemp = ""
    
     'Um zu erkennen, ob eine Zeile komplett leer/ungebraucht ist
     'verketten wir einfach alle Spalteninhalte der Zeile miteinander.
     'Ist die zusammengesetzte Zeichenkette aller Spalten leer,
     'ist die Zeile nicht genutzt...
     For i = 1 To iCONST_ANZAHL_EINGABEFELDER
         sTemp = sTemp & Trim(CStr(Tabelle1.Cells(lZeile, i).Text))
     Next i
    
     'Rückgabewert festlegen
     If Trim(sTemp) = "" Then
         'Die Zeile ist leer
         IST_ZEILE_LEER = True
     Else
         'Die Zeile ist mindestens in einer Spalte gefüllt
         IST_ZEILE_LEER = False
     End If
    
End Function


Erläuterung einiger Quelltext-Abschnitte im Detail

Hinweis zu den folgenden Abschnitten
Ich versuche auf so viele Grundlagen-Informationen und Techniken einzugehen wie möglich. Die vollständigen Grundlagen sind jedoch für ein kleines Tutorial viel zu umfangreich. Wenn Sie noch nicht so lange mit VBA arbeiten, werfen Sie vorher lieber einen Blick in die VBA Grundlagen und grundlegenden Programmiertechniken.
In den folgenden erläuternden Abschnitten habe ich alle Kommentare im Quelltext (grüne Schrift) zur besseren Lesbarkeit entfernt. So sehen Sie auch, dass gar nicht viel Quelltext benötigt wird.

Parametrisierung im Detail
Zuerst möchte ich auf das Thema Parametrisierung eingehen. In unserem kleinen Beispiel haben wir zwei sogenannte Konstanten im Einsatz. Schauen wir uns den dazugehörigen Quelltext-Ausschnitt an:

Private Const iCONST_ANZAHL_EINGABEFELDER As Integer = 6
Private Const lCONST_STARTZEILENNUMMER_DER_TABELLE As Long = 2


Die Konstante iCONST_ANZAHL_EINGABEFELDER wird dazu verwendet, die Anzahl der Eingabefelder flexibel zu gestalten. Die Programmierung ist so gebaut, dass die verwendeten Steuerelemente (TextBoxen) durchnummeriert sind. So können wir diese einfach mit einer Schleife abarbeiten lassen. Möchten wir bspw. noch 2 weitere Spalten in der Tabelle und ebenfalls 2 TextBoxen auf der Eingabemaske ergänzen, so reichen drei kleine Schritte aus:
  • Die Konstante iCONST_ANZAHL_EINGABEFELDER von 6 auf 8 erhöhen
  • In der Excel®-Tabelle 2 neue Spalten am Ende der Tabelle ergänzen
  • Auf der Oberfläche (UserForm1) einfach zwei neue TextBoxen platzieren mit den Namen TextBox7 und TextBox8
Das war es schon. Die Verarbeitungsroutinen sind so gebaut, dass keine weitere Anpassung notwendig ist. Diese Art von Programmierung, sprich die Steuerung der Verarbeitung durch einstellbare Konstanten, nennt man Parametrisierung. Diese Vorgehensweise macht eine Erweiterung natürlich sehr einfach, auch wenn die Erstellung etwas komplizierter ist als ohne Parametrisierung.

Der Vollständigkeit halber: die Konstante lCONST_STARTZEILENNUMMER_DER_TABELLE wird verwendet um die Zeilennummer des ersten Datensatzes festzulegen. Es gibt einige Excel®-Tabellen, wo über einer Tabelle bspw. noch eine größere Überschrift oder Summenformeln ergänzt werden oder auch mehrere Zeilen als Überschrift verwendet werden. In diesem Fall müsste man jede Verarbeitungsschleife, die normalerweise in Zeile 2 starten würde, manuell auf die entsprechende tatsächliche Startzeile abändern. Verwendet man stattdessen eine Konstante, so reicht die Anpassung an einer Stelle aus. Die Verarbeitungsroutinen gestaltet man entsprechend mit der Konstanten anstatt mit einer festen "2" im Quelltext.


Die Liste-Laden-Routine im Detail
Schauen wir uns wieder zuerst den dazugehörigen Quelltext-Ausschnitt an:

Private Sub LISTE_LADEN_UND_INITIALISIEREN()
   Dim lZeile As Long
   Dim lZeileMaximum As Long
   Dim i As Integer
  
     For i = 1 To iCONST_ANZAHL_EINGABEFELDER
         Me.Controls("TextBox" & i) = ""
     Next i

     ListBox1.Clear
     ListBox1.ColumnCount = 4
     ListBox1.ColumnWidths = "0;;;"
    
     lZeileMaximum = Tabelle1.UsedRange.Rows.Count
     For lZeile = lCONST_STARTZEILENNUMMER_DER_TABELLE To lZeileMaximum
         If IST_ZEILE_LEER(lZeile) = False Then
             ListBox1.AddItem lZeile
             ListBox1.List(ListBox1.ListCount - 1, 1) = CStr(Tabelle1.Cells(lZeile, 1).Text)
             ListBox1.List(ListBox1.ListCount - 1, 2) = CStr(Tabelle1.Cells(lZeile, 2).Text)
             ListBox1.List(ListBox1.ListCount - 1, 3) = CStr(Tabelle1.Cells(lZeile, 3).Text)
         End If
     Next lZeile
    
End Sub


Gehen wir den Quelltext Schritt für Schritt gemeinsam durch.

Nach den Variablendeklarationen (Zeilen die mit Dim starten) werden alle TextBoxen auf der Oberfläche geleert. Dieser Schritt kann theoretisch weggelassen werden, es gibt aber manchmal Anwendungen, wo solche Initialisierungen benötigt werden.
Die Schleife funktioniert recht einfach. Wir zählen sozusagen von 1 bis iCONST_ANZAHL_EINGABEFELDER (also von 1 bis 5), da der Wert der Konstante auf 5 gesetzt ist. Hier sieht man den Effekt der Parametrisierung. Ändern wir den Konstantenwert von 5 auf 7, wird von 1 bis 7 gezählt.

Innerhalb der Schleife wird nun mittels Me.Controls auf ein Steuerelement der Eingabeoberfläche UserForm1 zugegriffen. In den Klammern wird der Name des Steuerelements zusammengesetzt.

Beim 1. Schleifendurchlauf ist i = 1 und somit wäre der ausgefüllte Befehl dann: Me.Controls("TextBox1") = ""
Beim 2. Schleifendurchlauf ist i = 2 und somit wäre der ausgefüllte Befehl dann: Me.Controls("TextBox2") = ""
...
Beim 5. Schleifendurchlauf ist i = 5 und somit wäre der ausgefüllte Befehl dann: Me.Controls("TextBox5") = ""

Anschließend wird die Liste (ListBox1) geleert und entsprechend initialisiert. Hier erhöhen wir die angezeigten Spalten auf 4 und setzen anschließend die angezeigten Spaltenbreiten fest.

ListBox1.ColumnCount = 4
bestimmt die Spaltenanzahl der Liste.

ListBox1.ColumnWidths = "0;;;"
bestimmt die Spaltenbreiten der einzelnen Spalten der Liste.

Bei den Spaltenbreiten (ColumnWidths) muss man folgendes anmerken:
Die korrekte Syntax-Beschreibung für ColumnWidths lautet:
"<Breite Spalte 1>;<Breite Spalte 2>;<Breite Spalte 3>;<Breite Spalte 4>"

Bedeutet in unserem Beispiel:

<Breite Spalte 1> ist 0,
somit wird die Spalte ausgeblendet / unsichtbar dargestellt. Wir verwenden die ausgeblendete Spalte für die Zeilennummer des Datensatzes.

<Breite Spalte 2> ist leer,
die Spaltenbreite wird somit automatisch angepasst. Das Gleiche gilt für die Spaltenbreiten der Spalten 3 und 4.
Möchte man feste Spaltenbreiten vorgeben, so kann man diese natürlich wie folgt beziffern:
ListBox1.ColumnWidths = "0;100;50;150"

Kommen wir zur eigentlichen Einlese-Schleife aller Datensätze der Tabelle in unsere Liste.
Die Zeilennummer des ersten Datensatzes haben wir in einer Konstante bereits vorliegen. Die Zeilennummer des letzten Datensatzes müssen wir herausfinden. Dazu gibt es im Objektmodell die Eigenschaft: Tabelle1.UsedRange.Rows.Count. Diese Eigenschaft liefert uns die Zeilennummer der letzten genutzten Zeile der Tabelle1. Nun können wir die Schleife über alle Datensätze aufsetzen:

For lZeile = lCONST_STARTZEILENNUMMER_DER_TABELLE To lZeileMaximum

Für jede Zeilennummer, die wir nun in dieser Schleife durchlaufen, prüfen wir mit einer Hilfsfunktion IST_ZEILE_LEER(), ob in dieser Zeile irgendwo etwas eingetragen ist. Die Funktion liefert entweder "Die Zeile ist in Benutzung" (=False) oder "Die Zeile ist nicht benutzt" (=True) zurück.

Sollte die Zeile nicht leer, also in Benutzung, sein:

If IST_ZEILE_LEER(lZeile) = False Then

erzeugen wir einen neuen Eintrag in der Liste:

ListBox1.AddItem lZeile

In die erste Spalte der Liste übernehmen wir die Zeilennummer der Tabelle. So können wir immer direkt auf die zu bearbeitende Zeile zugreifen. Im ersten Tutorial haben wir eine ID-Spalte verwendet. Durch die Zeilennummer haben wir eine eindeutige Datensatzerkennung. Theoretisch könnte man auch mathematisch vorgehen und die Eintragsnummer der Liste in eine Zeilennummer umwandeln. Allerdings hat die Vorgehensweise mit der versteckten Zeilennummer den Vorteil, wenn später Such- oder Sortierfunktionen für die Liste ergänzt werden, dass dann keinerlei Anpassungen für die Verarbeitungsroutinen vorgenommen werden müssen. Wenn alle Einträge der Liste umsortiert werden, werden auch die Zeilennummern der ersten Spalte der Liste mit sortiert. So bleibt der Zugriff auf die richtige Zeile immer sicher.

Zusätzlich haben wir drei weitere Spalten in der Liste, die auch angezeigt werden. Diese befüllen wir mit den ersten 3 Spalten der Tabelle:

ListBox1.List(ListBox1.ListCount - 1, 1) = CStr(Tabelle1.Cells(lZeile, 1).Text)
ListBox1.List(ListBox1.ListCount - 1, 2) = CStr(Tabelle1.Cells(lZeile, 2).Text)
ListBox1.List(ListBox1.ListCount - 1, 3) = CStr(Tabelle1.Cells(lZeile, 3).Text)


Nachdem ein neuer Eintrag in die Liste mittels AddItem angelegt wurde, wird dieser standardmäßig unten angehangen. Somit können wir problemlos auf den letzten Eintrag zugreifen. Zu beachten ist, dass die Indexierung der List-Einträge nicht bei 1, sondern bei 0 beginnt. Der erste Eintrag hat also den Index 0. Somit hat der letzte Eintrag den Index "Anzahl Einträge" reduziert um 1: ListBox1.ListCount - 1. Um auf ein spezifisches Element der Liste zuzugreifen, gibt es die .List Methode.

ListBox1.List(<Index-Eitrag>,<Index-Spalte>)

ListBox1.List(0, 0)
ist der 1. Eintrag und die 1. Spalte. Auch bei den Spalten beginnt die Nummerierung bei 0 und nicht bei 1.

ListBox1.List(ListBox1.ListCount - 1, 2)
ist der letzte Eintrag und die 3. Spalte (Spalten-Index: 2) der Liste.

Somit haben wir die Liste vollständig mit allen anzuzeigenden Spaltenwerten befüllt und vorbereitet.


Die Eintrag-Laden-Routine im Detail
Werfen wir erneut einen Blick auf den betroffenen Quelltext-Ausschnitt:

Private Sub EINTRAG_LADEN_UND_ANZEIGEN()
   Dim lZeile As Long
   Dim i As Integer
    
     For i = 1 To iCONST_ANZAHL_EINGABEFELDER
         Me.Controls("TextBox" & i) = ""
     Next i
    
     If ListBox1.ListIndex >= 0 Then
         lZeile = ListBox1.List(ListBox1.ListIndex, 0)
         For i = 1 To iCONST_ANZAHL_EINGABEFELDER
             Me.Controls("TextBox" & i) = CStr(Tabelle1.Cells(lZeile, i).Text)
         Next i
     End If
    
End Sub


Nach der Variablendeklaration und dem bereits bekannten Reset der TextBoxen gibt es eine kleine Sicherheitsprüfung. Denn nur wenn ein Eintrag in der Liste markiert wurde, soll der markierte Datensatz geladen und angezeigt werden. Ansonsten sind die Eingabefelder ja bereits resettet und leer.

If ListBox1.ListIndex >= 0 Then

Hier wird abgefragt, ob der ListIndex unserer Liste entsprechend >= 0 ist. Wenn ein Eintrag markiert wurde, dann ist der Listen-Index immer >= 0. Wurde kein Eintrag markiert, so ist der Listen-Index = -1.

Ist also ein Eintrag selektiert, können wir die betroffene Zeilennummer des Datensatzes direkt auslesen, denn diesen haben wir in der unsichtbaren Spalte 1 unserer Liste versteckt.

lZeile = ListBox1.List(ListBox1.ListIndex, 0)

Mit einer kleinen Schleife über unsere Steuerelemente der Eingabemaske, die wir bereits aus der Laden-Routine der Liste kennen, können wir mit wenig Quelltext alle Werte des Datensatzes eintragen.

For i = 1 To iCONST_ANZAHL_EINGABEFELDER
   Me.Controls("TextBox" & i) = CStr(Tabelle1.Cells(lZeile, i).Text)
Next i

Die Zählvariable i verwenden wir für zwei Zwecke. Zum Einen als laufende Nummerierung für die TextBoxen, sprich TextBox1 bis TextBox5, und zum Anderen für die auszulesenden Spalten der Tabelle, ebenfalls Spalte 1 bis Spalte 5. Zusätzlich wandelt die Funktion CStr() den Inhalt der Tabellen-Zelle in eine Zeichenfolge um. Theoretisch kann man dieses sogenannte explizite Type-Casting auch weglassen. Aber ich möchte so viele Informationen und Fakten wie möglich erläutern. Daher baue ich manchmal auch zusätzliche Dinge ein, die man theoretisch auch nicht benötigt. Es schadet aber nicht, diese Befehle oder Ergänzungen beizubehalten.

Auch hier wieder der Verweis auf eine Parametrisierung. Durch die Konstante wird die Schleife automatisch erweitert, wenn wir neue Spalten in der Tabelle und neue Steuerelemente auf der Oberfläche ergänzen. Die Laden-Routine muss dann nicht mehr angepasst werden.

Damit ist unsere Laden-Routine vollständig.


Die Eintrag-Speichern-Routine im Detail
Werfen wir wieder einen Blick auf den betroffenen Quelltext-Ausschnitt:

Private Sub EINTRAG_SPEICHERN()
  Dim lZeile As Long
  Dim i As Integer
 
     If ListBox1.ListIndex = -1 Then Exit Sub
   
     lZeile = ListBox1.List(ListBox1.ListIndex, 0)
    
     For i = 1 To iCONST_ANZAHL_EINGABEFELDER
         Tabelle1.Cells(lZeile, i) = Me.Controls("TextBox" & i)
     Next i
    
     ListBox1.List(ListBox1.ListIndex, 1) = TextBox1
     ListBox1.List(ListBox1.ListIndex, 2) = TextBox2
     ListBox1.List(ListBox1.ListIndex, 3) = TextBox3
    
End Sub


Auf den ersten Blick sieht es ja fast genauso aus wie bei der Laden-Routine. Und ja, es ist auch so. Lediglich die Prüfung, ob ein Eintrag in der Liste markiert wurde, ist auf einer andere Variante realisiert.

If ListBox1.ListIndex = -1 Then Exit Sub

Bedeutet: Wenn der ListIndex = -1 ist, so ist auch kein Eintrag markiert und wir brechen die Verarbeitung dieser Routine mit dem Befehl Exit Sub ab.

Die Schleife über alle Steuerlemente / Spalten ist auch identisch. Nur laden wir diesmal nicht die Werte der Tabelle in die TextBoxen, sondern machen es genau anders herum.

Tabelle1.Cells(lZeile, i) = Me.Controls("TextBox" & i)

Wir speichern die Inhalte der TextBoxen in die Zellen der Tabelle.

Und schon sind wir in der Speichern-Routine fertig.


Die Eintrag-Hinzufügen-Routine im Detail
Werfen wir erneut einen Blick auf den betroffenen Quelltext-Ausschnitt:

Private Sub EINTRAG_ANLEGEN()
  Dim lZeile As Long
    
     lZeile = lCONST_STARTZEILENNUMMER_DER_TABELLE
     Do While IST_ZEILE_LEER(lZeile) = False
         lZeile = lZeile + 1
     Loop
    
     Tabelle1.Cells(lZeile, 1) = CStr("Neuer Eintrag Zeile " & lZeile)
    
     ListBox1.AddItem lZeile
     ListBox1.List(ListBox1.ListCount - 1, 1) = CStr("Neuer Eintrag Zeile " & lZeile)
     ListBox1.List(ListBox1.ListCount - 1, 2) = ""
     ListBox1.List(ListBox1.ListCount - 1, 3) = ""
    
     ListBox1.ListIndex = ListBox1.ListCount - 1
    
     TextBox1.SetFocus
     TextBox1.SelStart = 0
     TextBox1.SelLength = Len(TextBox1)
    
End Sub


Um einen neuen Eintrag hinzuzufügen, müssen wir zuerst die erste leere Zeile in der Tabelle finden. Normalerweise wird diese am Tabellenende sein... aber für den Fall der Fälle nehmen wir die erste leere Zeile, die wir finden. Dafür starten wir mit einer Schleife bei der Zeile des ersten Datensatzes (Konstante lCONST_STARTZEILENNUMMER_DER_TABELLE).

lZeile = lCONST_STARTZEILENNUMMER_DER_TABELLE

Wir prüfen nun für jede Zeile unter Verwendung unserer Hilfsfunktion IST_ZEILE_LEER(), ob wir eine leere Zeile gefunde haben. Sobald wir eine leere Zeile gefunden haben, wird die Schleifenverarbeitung beendet. Ist die aktuell geprüfte Zeile nicht komplett leer, wird die nächste Zeile geprüft.

Do While IST_ZEILE_LEER(lZeile) = False
   lZeile = lZeile + 1
Loop


Mit der ersten leeren Zeile in unserer Tabelle (die Zeilennummer ist jetzt in der Variablen lZeile gespeichert) können wir nun einen neuen Eintrag erzeugen.

Zuerst schreiben wir einen Dummy-Text in die Tabelle.

Tabelle1.Cells(lZeile, 1) = CStr("Neuer Eintrag Zeile " & lZeile)

Jetzt befüllen wir - analog der Liste-Laden-Routine - unsere ListBox.

ListBox1.AddItem lZeile
ListBox1.List(ListBox1.ListCount - 1, 1) = CStr("Neuer Eintrag Zeile " & lZeile)
ListBox1.List(ListBox1.ListCount - 1, 2) = ""
ListBox1.List(ListBox1.ListCount - 1, 3) = ""

Die letzten beiden Spalten der Liste füllen wir mit einem leeren Wert.

Damit dem Benutzer die Arbeit mit der Eingabemaske auch etwas leichter fällt, selektieren wir ihm die erste TextBox und markieren zusätzlich den enthaltenen Vorschlagstext. So kann der Benutzer direkt mit der Dateneingabe loslegen.

TextBox1.SetFocus
TextBox1.SelStart = 0
TextBox1.SelLength = Len(TextBox1)

Damit sind wir auch mit dieser Routine am Ende angelangt.


Die Eintrag-Löschen-Routine im Detail
Und zu guter Letzt noch einmal der betroffene Quelltext-Ausschnitt:

Private Sub EINTRAG_LOESCHEN()
  Dim lZeile As Long
  
     If ListBox1.ListIndex = -1 Then Exit Sub
  
     If MsgBox("Sie möchten den markierten Datensatz wirklich löschen?", _
               vbQuestion + vbYesNo, "Sicherheitsabfrage!") = vbYes Then
  
         lZeile = ListBox1.List(ListBox1.ListIndex, 0)
         Tabelle1.Rows(CStr(lZeile & ":" & lZeile)).Delete
         ListBox1.RemoveItem ListBox1.ListIndex
    
     End If
    
End Sub


Nach der bereits bekannten Prüfung, ob ein Eintrag in der Liste selektiert ist, präsentieren wir dem Benutzer eine Sicherheitsabfrage mit dem Befehl MsgBox.

If MsgBox("Sie möchten den markierten Datensatz wirklich löschen?", _
               vbQuestion + vbYesNo, "Sicherheitsabfrage!") = vbYes Then


Wenn der Benutzer nun auf "JA" klickt, trifft die Bedingung zu und wir dürfen den Datensatz lsöchen. Ansonsten passiert gar nichts, weil der ganze Quelltext-Block einfach übersprungen wird, bis zum End If.

Das eigentliche Löschen ist schnell gemacht. Dazu ermitteln wir die Zeilennummer des selektierten Eintrags der Liste aus unserer unsichtbaren Spalte.

lZeile = ListBox1.List(ListBox1.ListIndex, 0)

Nun löschen wir die gesamte Zeile in der Tabelle.

Tabelle1.Rows(CStr(lZeile & ":" & lZeile)).Delete

Und löschen den markierten Eintrag in unserer Liste.

ListBox1.RemoveItem ListBox1.ListIndex

Jetzt ist der Datensatz gelöscht und wir sind bereits am Routinen-Ende angelangt.


Eine Schaltfläche erstellen, welche die Eingabemaske öffnet

Auch hier möchte ich auf das erste Tutorial verweisen.
Dort ist ausführlich mit Screenshots erläutert, wie man eine entsprechende Start-Schaltfläche erstellen kann.

Jetzt testen wir!

Nun ist es soweit! Wir probieren das Ganze aus.
Klicken Sie auf unsere Start-Schaltfläche um die Eingabemaske zu öffnen und probieren Sie alles in Ruhe aus.

Schlusswort

Ich hoffe, ich konnte Ihnen an diesem etwas ausführlicheren Quelltext-Beispiel Version 2 die zweiten Schritte zur eigenen Eingabemaske etwas genauer erläutern. Selbstverständlich gibt es noch viele weitere Möglichkeiten, Erweiterungen und Verschönerungen, die man einbauen kann.

Ich wünsche Ihnen Viel Erfolg und Spass bei Ihrer ersten eigenen Eingabemaske Version 2!

Download der Beispieldatei

Zu guter Letzt habe ich Ihnen die in diesem Tutorial als Beispiel verwendete Datei auch wieder als Download bereitgestellt.
Den Link dazu finden Sie hier: Beispieldatei-Download
(Dateiformat: *.xlsm - Erstellt mit Microsoft® Excel® Version 2016 - Diese Datei ist kompatibel mit Microsoft® Excel® Version 2007 oder neuer - Dateigröße: ca. 31 KiloBytes)
Wichtiger Hinweis: Als kostenlosen Service stellen die Autoren von www.Online-VBA.de Dateien zum Download bereit. Dieser Download erfolgt stets auf eigene Gefahr. Bitte beachten Sie die Nutzungsbedingungen und das Impressum von www.Online-VBA.de, bevor Sie die Datei herunterladen. Ein kostenloser Support oder Service für die unter www.Online-VBA.de veröffentlichen Werke kann leider nicht angeboten werden!


Autor: Marc Wershoven (Oktober 2017)

Anzeige

VBA Programmierer gesucht?
http://www.WershovenOnline.de

Anzeige

Der Quick E-Mail Support von WershovenOnline®

Schnelle Hilfe bei Fragen rund um Microsoft® Office und VBA Makros

Der Quick E-Mail Support von WershovenOnline® Sie haben beispielsweise eine Frage zu einer Ihrer eigenen Makroprogrammierungen in VBA? Oder Sie suchen Unterstützung und Informationen über eine bestimmte Microsoft® Excel® Formel? Bei nahezu allen Fragen und Problemen rund um Microsoft® Office und VBA Makros steht Ihnen unser individueller Quick E-Mail Support zur Verfügung. Einfach, schnell und unkompliziert Ihre Frage in einer E-Mail formulieren, mit oder ohne Screenshots oder einer Beispieldatei absenden und kurze Zeit später haben Sie eine vollständige Lösung inkl. ausführlicher Erklärung vom Profi in Ihrem Postfach! Zusätzlich besteht die Option, dass wir uns mittels Fernwartung (selbstverständlich nach Ihrem Einvertändnis) direkt "live" mit Ihnen zusammen an Ihrem Bildschirm gemeinsam Fragen und Problemstellungen anschauen und lösen können!

Weitere Informationen zu diesem kostenpflichtigen Angebot finden Sie auf der Anbieterseite von WershovenOnline® auf www.wershovenonline.de.

Zum Anbieter des Quick-E-Mail-Support...

Zum Seitenanfang