Datum schnell per Tastatur einstellen

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).

Herkömmliches Textfeld mit Datum

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.

Markierung des Tages

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

Schreibe einen Kommentar