Die Eingabe von Datumsangaben ist erstens manchmal unkomfortabel und zweitens passiert es oft, dass Benutzer das Datum im falschen Format eingeben. Dem wollen wir mit der Lösung aus diesem Beitrag vorbeugen, indem wir die Eingabe vollständig über die Tasten „Nach oben“, „Nach unten“, „Nach rechts“ und „Nach links“ ermöglichen. Sobald der Benutzer den Fokus auf ein Datumsfeld setzt, wird das aktuelle Datum eingesetzt, sofern das Feld noch leer ist. Dann kann er mit „Nach links“ und „Nach rechts“ zwischen den einzelnen Datumsbestandteilen Tag, Monat und Jahr wechseln und mit den Tasten „Nach oben“ und „Nach unten“ stellt er schrittweise den gewünschten Wert ein. Die Funktionalität bilden wir anschließend auch noch in einer Klasse ab, sodass die Funktion einfach mit zwei Zeilen Code zu einem Datums-Textfeld hinzugefügt werden kann.
Datumsfelder sind keine Hexerei. Man legt das Datumfeld in einer Tabelle an und legt die Tabelle als Datensatzquelle für ein Formular fest.
In diesem zieht man das Datumsfeld in den Formularentwurf und kann dieses direkt nutzen. Die Eingabe wird sogar vereinfacht durch das Anklicken des kleinen Kalender-Icons neben dem Textfeld (siehe Bild 1).

Bild 1: Herkömmliches Textfeld mit Datum
Wenn man hier allerdings einen Standardwert wie das aktuelle Datum vorgibt und der Benutzer soll dann sein Geburtsdatum eingeben, wird er schnell auf dieses Calendar-Widget verzichten. Denn dort müsste er endlos klicken, bis er zum Beispiel ein Datum erreicht, dass viele Jahre zurückliegt.
Auch die manuelle Datumseingabe birgt Tücken, denn hier muss das Format eingehalten werden. Das ist kein Hexenwerk, dennoch kommt es dabei immer wieder zu Fehleingaben.
Also stellen wir in diesem Beitrag eine Lösung vor, mit der wir das Datum ganz einfach eingeben können – nämlich allein mit den Cursor-Tasten, also Nach oben, Nach unten, Nach links und Nach rechts.
Dabei sollen gleich beim Fokuserhalt wie in Bild 2 die Tage markiert werden. Damit weiß der Benutzer, dass er nun die Tage für das gewünschte Datum einstellen kann. Er braucht nur noch den gewünschten Wert für den Tag mit den Tasten Nach oben und Nach unten einzustellen.

Bild 2: Markierung des Tages
Dann betätigt er die Taste Nach rechts, um zum Monat zu wechseln, und legt auf die gleiche Weise wie beim Tag den Monat fest.
Schließlich springt er mit Nach rechts zu den Jahren und wählt auch noch das Jahr aus. Hierbei haben wir noch eine Komfortfunktion eingebaut, mit welcher der Benutzer bei gedrückter Umschalt-Taste 10 Jahre vor- oder zurückspringen kann.
Möchte man anschließend den Tag oder den Monat korrigieren, kann man diese mit der Nach links-Taste erneut ansteuern.
Programmierung der Lösung
In die Umsetzung der Lösung sind einige Ereignisse des Textfeld-Steuerelements involviert. Als Erstes benötigen wir ein Ereignis, mit dem wir direkt beim Setzen des Fokus auf das Textfeld dafür sorgen, dass die ersten beiden Zeichen für die Angabe des Tages selektiert werden.
Hier bietet sich das Ereignis Bei Fokuserhalt des Steuerelements an, für das wir die folgende Ereignisprozedur hinterlegen:
Private Sub txtGeburtsdatum_GotFocus() Call txtGeburtsdatumAktivieren End Sub
Diese ruft eine Prozedur namens txtGeburtsdatumAktivieren auf. Wir lagern die Funktion des Ereignisses in eine eigene Prozedur aus, weil wir diese später noch von einer anderen Stelle aus aufrufen wollen.
Die Prozedur txtGeburtsdatumAktivieren nimmt einen Parameter namens intDatePart mit dem Datentyp eDatePart entgegen. Mit diesem können wir festlegen, welcher Teil des Datums – Tag, Monat oder Jahr – markiert werden soll. Die Enumeration definieren wir wie folgt:
Public Enum eDatePart
datepartday = 0
datepartmonth = 1
datepartyear = 2
End Enum
Dann referenziert die Prozedur das Textfeld txtGeburtsdatum mit der Variablen txt. Dann prüft sie, ob das Textfeld leer ist, und trägt in diesem Fall das aktuelle Datum ein.
Das können Sie beliebig anpassen, wenn für den jeweiligen Anwendungsfall ein anderes Datum angezeigt werden soll. Schließlich ruft die Prozedur noch eine weitere Routine namens SelectDatePart auf und übergibt dieser einen Verweis auf das Textfeld und leitet den optionalen Parameter intDatePart weiter:
Private Sub txtGeburtsdatumAktivieren(Optional intDatePart As eDatePart) Dim txt As TextBox Set txt = Me.txtGeburtsdatum If IsNull(txt) Then txt.Value = Date End If Call SelectDatePart(txt, intDatePart) End Sub
Selektieren eines Datumsteils
Die Prozedur SelectDatePart nimmt einen Verweis auf das Textfeld entgegen, sowie einen Wert der Enumeration eDatePart, mit dem angegeben wird, ob der Tag, der Monat oder das Jahr selektiert werden soll.
Sie prüft, welchen Wert intCurrentDatePart hat, und stellt abhängig davon die beiden Eigenschaften SelStart und SelLength des mit txt übergebenen Textfeldes ein. Wir gehen dabei davon aus, dass das Datum im Textfeld immer im Format dd.mm.yyyy formatiert ist.
Für den Tag wird SelStart mit dem Wert 0 auf das erste Zeichen eingestellt und die Länge der Markierung auf zwei Zeichen, für den Monat auf die Position 3 und die Länge 2 und für das Jahr auf die Position 6 und die Länge 4:
Private Sub SelectDatePart(txt As TextBox, _ intCurrentDatePart As eDatePart) Select Case intCurrentDatePart Case datepartday txt.SelStart = 0 txt.SelLength = 2 Case datepartmonth txt.SelStart = 3 txt.SelLength = 2 Case datepartyear txt.SelStart = 6 txt.SelLength = 4 End Select End Sub
Damit ist der erste Teil bereits erledigt – beim Fokuserhalt des Textfeldes wird gegebenenfalls das aktuelle Datum eingetragen und die ersten beiden Stellen für den Tag werden markiert.
Bewegen der Markierung im Datumsfeld
Um die Eingaben des Benutzers im Datumsfeld zu erfassen, vor allem die Nutzung der Tasten Nach oben, Nach unten, Nach links und Nach rechts, verwenden wir das Ereignis Bei Taste ab des Textfeldes. Die entsprechende Ereignisprozedur liefert beim Aufruf zwei Parameter:
- KeyCode: Code der betätigten Taste
- Shift: Angabe, ob die Umschalt-, Strg– oder Alt-Taste betätigt wurde
Damit können wir sauber erfassen, wie der Benutzer über die Tastatur mit dem Textfeld arbeitet. Im ersten Schritt der Prozedur, deren ersten Teil wir in Listing 1 finden, deaktivieren wir mit Me.Painting = False das Neuzeichnen des Formulars, bis die Eingabe abgeschlossen ist.
Private Sub txtGeburtsdatum_KeyDown(KeyCode As Integer, Shift As Integer) Dim txt As TextBox Dim intCurrentDatePart As eDatePart Dim lngDay As Long Dim lngMonth As Long Dim lngYear As Long Dim lngYears As Long Me.Painting = False Set txt = Me.txtGeburtsdatum lngDay = Day(txt.Value) lngMonth = Month(txt.Value) lngYear = Year(txt.Value) intCurrentDatePart = GetCurrentDatePart(txt) If Shift = acShiftMask Then lngYears = 10 Else lngYears = 1 End If Select Case KeyCode Case vbKeyLeft, vbKeyRight Select Case KeyCode Case vbKeyLeft Select Case intCurrentDatePart Case datepartday intCurrentDatePart = datepartyear Case datepartmonth intCurrentDatePart = datepartday Case datepartyear intCurrentDatePart = datepartmonth End Select Case vbKeyRight Select Case intCurrentDatePart Case datepartday intCurrentDatePart = datepartmonth Case datepartmonth intCurrentDatePart = datepartyear Case datepartyear intCurrentDatePart = datepartday End Select End Select Call SelectDatePart(txt, intCurrentDatePart) KeyCode = 0 ...
Listing 1: Navigieren im Datum und Anpassen der einzelnen Datumsteile (Teil 1)
Danach referenzieren wir mit der Variablen txt das Textfeld txtGeburtsdatum. Den Inhalt des Textfeldes untersuchen wir in den nächsten drei Anweisungen, um mit den Funktionen Day, Month und Year den Tag, den Monat und das Jahr zu ermitteln.
Danach rufen wir eine Hilfsfunktion namens GetCurrentDatePart auf, der wir einen Verweis auf das Textfeld übergeben. Sie soll bestimmen, ob gerade der Tag, der Monat oder das Jahr im Textfeld markiert ist. Dazu ermittelt sie die Startposition der Markierung und speichert sie in der Variablen lngSelStart.
Dann prüft sie, ob sich die Position zwischen 0 und 2 befindet (Tag), zwischen 3 und 5 (Monat) oder zwischen 6 und 9 (Jahr), und schreibt die entsprechende Konstante der Enumeration eDatePart in die Variable intCurrentDatePart. Dieser Wert wird schließlich zurückgegeben:
Private Function GetCurrentDatePart(txt As TextBox) _ As eDatePart Dim lngSelStart As Long Dim intCurrentDatePart As eDatePart lngSelStart = txt.SelStart Select Case True Case lngSelStart >= 0 And lngSelStart <= 2 intCurrentDatePart = datepartday Case lngSelStart >= 3 And lngSelStart <= 5 intCurrentDatePart = datepartmonth Case lngSelStart >= 6 And lngSelStart <= 9 intCurrentDatePart = datepartyear End Select GetCurrentDatePart = intCurrentDatePart End Function
Die Ereignisprozedur txtGeburtsdatum_KeyDown prüft nun, ob der Benutzer derzeit die Umschalttaste gedrückt hält, und speichert in diesem Fall den Wert 10 in der Variablen lngYears, sonst den Wert 1. Dies dient dazu, dass wir später beim Ändern der Jahreszahl entweder in Einerschritten oder Zehnerschritten arbeiten können.
Nun beginnt die eigentliche Untersuchung der betätigten Taste. Dazu verwenden wir eine Select Case-Bedingung, deren zu vergleichender Wert der Inhalt des Parameters KeyCode ist.
Im ersten Teil prüfen wir, ob der Benutzer die Taste Nach links oder Nach rechts gedrückt hat. In diesem Fall treffen wir in einer weiteren Select Case-Bedingung eine weitere Unterscheidung. Der erste Case-Zweig wird für die Nach links-Taste angesteuert (vbKeyLeft).
Darin finden wir eine weitere Select Case-Bedingung, in der wir den Wert von intCurrentDatePart untersuchen, also ob die Markierung gerade den Tag, den Monat oder das Jahr enthält. Im ersten Case-Zweig vergleichen wir mit datepartday. In diesem Fall stellen wir intCurrentDatePart auf datepartyear ein, damit die Markierung auf das Jahr eingestellt werden kann. Beim Monat springen wir zum Tag, beim Jahr zum Monat.
Ende des frei verfügbaren Teil. Wenn Du mehr lesen möchtest, hole Dir ...
den kompletten Artikel im PDF-Format mit Beispieldatenbank
diesen und alle anderen Artikel mit dem Jahresabo
