Textfeld nur mit bestimmten Zeichen füllen

Manche Felder in Tabellen dürfen nur bestimmte Zeichen aufnehmen. So soll beispielsweise eine Postleitzahl nur aus Zahlen bestehen, Namen sollen keine Zahlen enthalten, Telefonnummern nur Zahlen und bestimmte Zeichen wie Plus, Minus und Klammern. Um dies durchzusetzen, gibt es verschiedene Möglichkeiten. Die einfachste ist, nach der Eingabe zu prüfen, ob das Feld nur die zulässigen Zeichen enthält und den Benutzer darauf hinzuweisen. Man könnte aber auch direkt bei der Eingabe nur die zulässigen Zeichen akzeptieren. Dabei gibt es jedoch einige Fallstricke. In diesem Beitrag schauen wir uns die verschiedenen Möglichkeiten an.

Prüfung nach der Eingabe

Die einfachste Variante ist wohl die, direkt nach der Eingabe zu prüfen, ob der Text nicht erlaubte Zeichen enthält. Dazu müssen wir zunächst einmal definieren, welche Zeichen erlaubt sind und welche nicht. Ein einfaches Beispiel ist die Postleitzahl. Sie darf nur Zahlen enthalten, was leicht zu erreichen wäre, wenn man das Feld, an das man das Textfeld zur Eingabe bindet, direkt als Zahlenfeld definieren würde.

Postleitzahlen enthalten aber auch mal führende Nullen, und die werden eben nur bei Verwendung eines Felddatentyps wie Kurzer Text gespeichert. Es geht zwar auch mit einem Zahlenfeld und bestimmten Formatierungen, aber spätestens beim Export in eine Textdatei, etwa zum Übergeben von Adressen, werden standardmäßig nur die tatsächlich gespeicherten Werte übergeben.

Wir haben eine kleine Tabelle namens tblBeispielfelder erstellt, die drei Felder namens PLZ, Telefon und EMail für uns als Spielmaterial enthält. Diese binden wir über die Eigenschaft Datensatzquelle an ein neues Formular.

Wir definieren als Erstes eine Konstante, die alle zulässigen Zeichen enthält:

Const cStrZahlen As String = "0123456789"

Dann hinterlegen wir für das Ereignis Vor Aktualisierung des Textfeldes txtPLZ, das an das Feld PLZ gebunden ist, die Ereignisprozedur aus Listing 1. Diese liest den Inhalt des Textfeldes txtPLZ in die Variable strPLZ ein und ersetzt einen eventuellen Nullwert durch eine leere Zeichenkette. Dann untersucht sie in einer For…Next-Schleife alle Buchstaben der Zeichenkette strPLZ. Dabei ermittelt sie den aktuellen Buchstaben mit Mid(strPLZ, i, 1) und prüft dann mit der InStr-Funktion, ob dieser in der Zeichenkette aus cStrZahlen enthalten ist. Ist das nicht der Fall, liefert InStr die Position, die gleich 0 ist. Dann erscheint eine entsprechende Meldung und die Eingabe wird mit Cancel = True abgebrochen – der Benutzer kann das Feld erst verlassen, wenn die Prüfung erfolgreich ist (siehe Bild 1). Dazu kann das Feld auch vollständig geleert werden.

Meldung nach dem Vor Aktualisierung-Ereignis

Bild 1: Meldung nach dem Vor Aktualisierung-Ereignis

Private Sub txtPLZ_BeforeUpdate(Cancel As Integer)
     Dim i As Integer
     Dim strPLZ As String
     strPLZ = Nz(Me!PLZ, "")
     For i = 1 To Len(strPLZ)
         If InStr(1, cStrZahlen, Mid(strPLZ, i, 1)) = 0 Then
             MsgBox "Die PLZ darf nur aus Zahlen bestehen.", vbOKOnly + vbExclamation, "Ungültige PLZ"
             Cancel = True
         End If
     Next i
End Sub

Listing 1: Prüfen der PLZ nach der Eingabe

Prüfung während der Eingabe

Die alternative Variante ist, die Zeichen direkt bei der Eingabe zu prüfen. Dazu benötigen wir eine andere Ereignisprozedur, nämlich Bei Taste ab. Vorab ein Hinweis: Damit decken wir nicht alle Fälle ab. Dazu jedoch später mehr.

Da wir auch erst einmal die Eingabe der Postleitzahl beschreiben wollen, kopieren wir das Feld txtPLZ in ein neues Textfeld namens txtPLZ2. Für dieses hinterlegen wir dann die Ereignisprozedur txtPLZ2_KeyDown. Was können wir mit dem Ereignis Bei Taste ab erledigen?

Die dadurch ausgelöste Prozedur txtPLZ2_KeyDown ist so aufgebaut:

Private Sub txtPLZ2_KeyDown(KeyCode As Integer,  Shift As Integer)
End Sub

Hier sehen wir zwei Parameter:

  • KeyCode: Liefert einen Zahlenwert, der die betätigte Taste repräsentiert.
  • Shift: Gibt an, ob eine der Tasten Umschalt, Alt oder Strg gedrückt ist.

KeyCode liefert aber nicht nur einen Zahlenwert für die aktuell angeklickte Taste. Sie können durch Einstellen von KeyCode auf den Wert 0 auch dafür sorgen, dass der Tastenanschlag nicht an das aktuelle Steuerelement weitergeleitet wird. Und Sie können sogar festlegen, dass statt des gedrückten Zeichens ein anderes Zeichen weitergegeben wird. Für uns ist allerdings nur interessant, die Eingabe eines nicht gewünschten Zeichens zu unterbinden, indem wir KeyCode auf 0 einstellen.

Wie finden wir heraus, welcher KeyCode welchem Zeichen entspricht, um entsprechend darauf reagieren zu können? Ganz einfach: Wir geben den KeyCode einfach im Direktbereich aus.

Private Sub txtPLZ2_KeyDown(KeyCode As Integer,  Shift As Integer)
     Debug.Print KeyCode
End Sub

Damit erfahren wir durch Eingeben von Zeichen in das Feld txtPLZ2 schnell, dass die Zahlen von 0 bis 9 den Werten 48 bis 57 für KeyCode entsprechen. Wir können nun in einem ersten Ansatz dafür sorgen, dass der Benutzer nur noch diese Zeichen in das Textfeld eingeben kann. Dazu prüfen wir, ob KeyCode einen Wert von 48 bis 57 enthält und falls nicht, geben wir mit dem Parameter KeyCode den Wert 0 zurück:

Private Sub txtPLZ2_KeyDown(KeyCode As Integer,  Shift As Integer)
     Select Case KeyCode
         Case 48 To 57
         Case Else
             KeyCode = 0
     End Select
End Sub

Das funktioniert genau wie angenommen: Nur die Tasten 0 bis 9 werden weitergeleitet und im Textfeld ausgegeben.

Wir haben allerdings ein kleines Problem: Auch die Tasten zum Bewegen der Einfügemarke, die Eingabetaste, die Tabulatortaste et cetera werden innerhalb des Textfeldes blockiert. Also geben wir auch solche Tasten wieder frei.

Wie Sie herausfinden, welche KeyCodes hinter den Tasten stecken, haben wir ja bereits beschrieben. Der Übersicht halber tragen wir die zusätzlichen Elemente in eine weitere Case-Bedingung ein:

  • 8: Back
  • 9: Tabulator
  • 13: Eingabetaste
  • 27: Escape
  • 37: Cursor nach links
  • 39: Cursor nach rechts
  • 46: Entfernen
  • 113: F2 (zum Aufheben von Markierungen)

Nummernblock berücksichtigen

Gegebenenfalls verwenden Benutzer auch den Nummernblock der Tastatur, um Zahlen einzugeben. Das müssen wir berücksichtigen, denn die KeyCode-Werte entsprechen nicht denen der normalen Zahlentasten, sondern den Zahlen von 96 bis 105. Wir fügen diese dem Case-Zweig für die normalen Zahlen hinzu:

        Case 48 To 57, 96 To 105

Die Eingabetaste im Nummernblock hat allerdings auch den KeyCode-Wert 13, sodass hier keine Erweiterung notwendig ist.

Die vollständige Prozedur sieht nun wie folgt aus:

Private Sub txtPLZ2_KeyDown(KeyCode As Integer,  Shift As Integer)
     Select Case KeyCode
         Case 48 To 57, 96 To 105
         Case 8, 9, 13, 27, 37, 39, 46, 113
         Case Else
             KeyCode = 0
     End Select
End Sub

Für bessere Lesbarkeit können wir auch die Konstanten der Enumeration KeyCodeConstants nutzen.

Bei der Gelegenheit fällt uns noch eine Ergänzung ein: Aktuell lassen wir alle Betätigungen der Tasten von 0 bis 9 zu – und wir prüfen noch nicht, ob der Benutzer dabei eine der Tasten Umschalt, Strg oder Alt drückt. Das heißt, dass der Benutzer die Zahlen auch bei gedrückter Umschalttaste eingeben kann, was die Eingabe von Ausrufezeichen, Anführungszeichen und so weiter erlaubt. Wir müssen also im Case-Zweig für die Zahlen noch prüfen, ob der Parameter Shift den Wert 0 enthält und falls nicht, das eingegebene Zeichen abfangen.

Dann sieht die Prozedur wie in Listing 2 aus.

Private Sub txtPLZ2_KeyDown(KeyCode As Integer, Shift As Integer)
     Select Case KeyCode
         Case vbKey0 To vbKey9, vbKeyNumpad0 To vbKeyNumpad9
             If Not Shift = 0 Then
                 KeyCode = 0
             End If
         Case vbKeyBack, vbKeyTab, vbKeyReturn, vbKeyEscape, vbKeyLeft, vbKeyRight, vbKeyDelete, vbKeyF2
         Case Else
             KeyCode = 0
     End Select
End Sub

Listing 2: Prüfen der PLZ nach der Eingabe mit KeyCode-Konstanten

Einfügen über die Zwischenablage

Der Fall, den wir mit dieser Methode nicht verarbeiten können, ist das Einfügen von Texten über die Zwischenablage. Das heißt, der Benutzer hat beispielsweise den Text D-12345 in die Zwischenablage kopiert, markiert dann das Textfeld txtPLZ2 und betätigt entweder die Tastenkombination Strg + V oder den Kontextmenübefehl Einfügen.

Als Erstes fällt auf: Wir haben die Tastenkombination Strg + V noch gar nicht freigeschaltet. Das ist etwas aufwendiger, da wir auch noch prüfen müssen, ob die Strg-Taste gleichzeitig gedrückt wird. Ob die Strg-Taste gedrückt wird, ermitteln wir wie bei der Umschalt-Taste und der Alt-Taste über den Parameter Shift. Shift kann die folgenden Werte annehmen, die auch kombiniert werden können:

  • 0: Keine Taste gedrückt.
  • 1: Umschalt-Taste
  • 2: Strg-Taste
  • 3: Umschalt– und Strg-Taste (1 plus 2)
  • 4: Alt-Taste
  • 5: Umschalt– und Alt-Taste (1 plus 4)
  • 6: Strg– und Alt-Taste (2 plus 4)
  • 7: Umschalt-, Strg– und Alt-Taste (1 plus 2 plus 4)

Auch hier gibt es entsprechende Konstanten. Allerdings verwenden wir nicht die der Enumeration KeyCodeConstants, sondern entsprechende Access-Konstanten:

  • Umschalt-Taste: acShiftMask
  • Strg-Taste: acCtrlMask
  • Alt-Taste: acAltMask

Die Betätigung der Tastenkombination lassen wir also mit dem folgenden Case-Zweig in der Select Case-Bedingung zu:

Case vbKeyC
     If Shift = acCtrlMask Then
     Else
         KeyCode = 0
     End If

Beim Betätigen des Buchstaben c prüfen wir also, ob der Benutzer dabei die Strg-Taste (acCtrlMask) betätigt hat. Falls dies nicht in Kombination mit der Strg-Taste geschehen ist, wird dies mit KeyCode = 0 unterbunden.

Aber was tun wir, wenn der Benutzer einen Text mit Strg + V einfügt? Wir könnten natürlich an dieser Stelle den Inhalt der Zwischenablage abgreifen und untersuchen. Aber wie machen es uns ein wenig einfacher. Die Lücke füllen wir durch das Setzen des Zeitgeberintervalls auf 100 Millisekunden:

If Shift = acCtrlMask Then
     Me.TimerInterval = 100
...

Ist TimerIntervall auf einen Wert größer als 0 gesetzt, wird im angegebenen Intervall das Ereignis Bei Zeitgeber ausgelöst. Für dieses hinterlegen wir die folgende Prozedur:

Private Sub Form_Timer()
     Dim i As Integer
     Dim strPLZ As String
     Dim strTemp As String
     strPLZ = Nz(Me!txtPLZ2.Text, "")
     If Not Len(strPLZ) = 0 Then
         For i = 1 To Len(strPLZ)
             If Not InStr(1, cStrZahlen,  Mid(strPLZ, i, 1)) = 0 Then
                 strTemp = strTemp & Mid(strPLZ, i, 1)
             End If
         Next i
     End If
     Me!txtPLZ2 = strTemp
     Me.TimerInterval = 0
End Sub

Was geschieht hier? Wenn der Benutzer beispielsweise den Text D-12345 aus der Zwischenablage in das Textfeld eingeben will, erkennt die KeyDown-Ereignisprozedur, dass er Strg + V betätigt hat. Der Text ist zu diesem Zeitpunkt aber noch nicht im Textfeld angekommen, sondern erst kurze Zeit später. Daher verwenden wir die Form_Timer-Ereignisprozedur, um den eingefügten Text auszuwerten.

Hier schreiben wir den Text aus dem Textfeld zunächst in die Variable strPLZ. Wir können nicht auf Me!txtPLZ2 zugreifen, sondern müssen Me!txtPLZ2.Text nutzen, da der Text noch nicht im Textfeld gespeichert wurde.

Danach durchlaufen wir eine For…Next-Schleife über alle Zeichen des hineinkopierten Textes und prüfen, ob es dort andere Zeichen als die Zahlen von 0 bis 9 gibt. Nur diese Zahlen werden an eine neue Zeichenkette namens strTemp angehängt. Wir prüfen also für jedes Zeichen, ob es eine Zahl ist, und übernehmen sie dann in strTemp.

Aus D-12345 in strPLZ wird also 12345 in strTemp. Diesen Wert schreiben wir dann zurück in das Textfeld.

Was geschieht beim Einfügen per Kontextmenü?

Es gibt auch noch die Möglichkeit, dass der Benutzer den Inhalt der Zwischenablage über den Befehl Einfügen aus dem Kontextmenü in das Textfeld kopieren will. Entwickler nutzen vermutlich überwiegend die Tastenkombination Strg + V, aber normale Benutzer verwenden vermutlich durchaus noch solche Kontextmenü-Befehle.

Wir können zwar den Rechtsklick auf das Textfeld abfangen, aber wir können nicht herausfinden, ob der Benutzer den Befehl Einfügen aus dem Kontextmenü auswählt.

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