Startseite Inhaltsverzeichnis Nutzungsbedingungen Datenschutz Impressum Weitere Informationen

TUTORIAL

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

VBA und Makros • Codeschnipsel • Tabelle • Eingabemaske • GUI • Einsteiger • Schritt für Schritt • Anleitung

Einleitung

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.

VBAVBA Codeschnipsel
XLSQuelltext zur Verwendung mit Microsoft® Excel®
DLOptional mit Beispieldatei(en) zum Download
TUTTutorials

Ausgangslage ... Was tut der Codeschnipsel?

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
 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
X 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 ersten 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 und Original-Quelltext unter:
' https://www.online-vba.de/vba_tutorialuserform_2.php
' Verwendung der Quelltexte auf eigene Gefahr!
' Es gelten die Nutzungsbedingungen von https://www.online-vba.de
' ****************************************************************


' ************************************************************************************************
' 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

PERSONAL-COACHING IN VBA?

ANZEIGE
Vervollständigen Sie Ihre Weiterbildung und erweitern Sie Ihr Wissen mit unseren professionellen Schulungen! Erhalten Sie Zugang zu wertvollen zusätzlichen Tipps und Lehrmaterial, das Ihnen hilft, Ihre Fähigkeiten auszubauen und selbst ein VBA-Profi zu werden. Unser exklusives Angebot bietet Ihnen außerdem die Möglichkeit, tiefer in ein spezifisches Thema Ihrer Wahl einzusteigen. Unser Personal-Training rund um VBA ist genau die richtige Ergänzung, um theoretische Aspekte gemeinsam in der Praxis anzuwenden und umzusetzen. Wir unterstützen und beraten Sie ebenfalls bei der VBA Programmierung in Ihren eigenen Projekten und stehen Ihnen mit Rat und Tat zur Seite. Setzen Sie sich einfach mit uns in Verbindung. Sie finden uns auf unserer Internetseite:

WershovenOnline.de

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 anderen 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 gefunden 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 löschen. 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!

PROGRAMIERER GESUCHT? ... UND GEFUNDEN!

ANZEIGE
Sie möchten komplexere oder umfangreichere Funktionen in Ihre VBA-Makros und Tools einbauen? Sie suchen einen Programmierer, der Ihre Ideen in die Tat umsetzt?

Sie haben uns gefunden! Unsere individuellen Auftragsprogrammierungen sind maßgeschneiderte Lösungen für Ihre spezifischen Anforderungen. Wir arbeiten eng mit Ihnen zusammen, um sicherzustellen, dass unsere Lösungen perfekt auf Ihre Bedürfnisse abgestimmt sind und Sie Ihre Wunsch-Software erhalten.

Kontaktieren Sie uns noch heute und lassen Sie uns gemeinsam Ihre individuelle Programmierung erstellen! Sie finden uns auf unserer Internetseite:

WershovenOnline.de

Download der Beispieldatei ...

Zu guter Letzt habe ich Ihnen die in diesem Tutorial als Beispiel verwendete Datei als Download bereitgestellt.

Den Link dazu finden Sie hier:

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!

Anmerkungen und Hinweise ...

Dieser Codeschnipsel wurde geschrieben von Marc Wershoven im Jahr 2017.
Es gelten die Nutzungsbedingungen von Online-VBA.de.
TOTOP
ANZEIGE