Maskiertes Textfeld

Hallo,

leider habe ich bei Mr. Google nicht so richtig was dazu gefunden…

ich habe eine Eingabeoberfläche (Word 2007) in welcher die Nutzer ein Aktenzeichen eingeben sollen. Dieses hat das Format xxx/xxxx/xxx/xxx bzw. xxx/9xx/xxxx/xxx (wenn also dort ne „9“ ist ist der Schrägstrich eins „früher“ als bei der anderen Version).
Nun möchte ich dem Nutzer die Eingabe erleichtern in dem er nicht die Schrägstriche mit eingeben braucht sondern das Programm ergänzt diese automatisch bei Eintragung von Zahlen. Nun habe ich bereits Code geschrieben (von dem ich denke das er recht kompliziert ist *g*) welcher dies mehr oder minder auch tut. Jedoch wenn ich mehrfach die „Rücktaste“ drücke (der Nutzer muss ja auch mal was ändern können und dann soll er die Schrägstriche ja nicht wieder anzeigen wenn er es gerade gelöscht hat) dann hängt sich irgendwie das Programm auf. Woran es liegen könnte: keine Ahnung. Wer kann mir helfen?

Hier der Code (Variablen habe ich noch nicht deklariert); das „txtAZ“ das Textfeld-Steuerelement ist dürfte den meisten klar sein :smile::

Private Sub txtAZ\_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger)
'nur Zahlen erlaubt
If KeyAscii 57 Then KeyAscii = 0
End Sub

Private Sub txtAZ\_Change()
T = txtAZ.Text

'löschen aller Schrägstriche
If InStr(1, T, "/") 0 Then
 Anfang = 1
 Do
 Schräg = InStr(Anfang, T, "/")
 Länge = Len(T)
 T = IIf(Schräg Länge, Left(T, Schräg - 1) & Right(T, Länge - Schräg), T)
 Loop Until InStr(1, T, "/") = 0
End If

Zähler = Array(3, 8, 12)

For I = 1 To 3
 x = IIf(Mid(T, 5, 1) = "9" And I = 2, 2, 1)
 If Len(T) \> Zähler(I - 1) - x + 1 Then
 t1 = Left(T, Zähler(I - 1) - x + 1)
 T2 = Right(T, Len(T) - (Zähler(I - 1) - x + 1))

 T = t1 & "/" & T2
 Else
 Exit For
 End If
Next

txtAZ.Text = T
End Sub

LG Tobi@s

Hallo Tobias.

dann hängt sich irgendwie das Programm auf.
Woran es liegen könnte: keine Ahnung

Möglicherweise liegt es daran, daß Du im Change-Ereignis der TextBox den Text der TextBox selbst änderst. Es bedeutet ja, daß sich das Ereignis selbst aufruft; es ist rekursiv.

Wahrscheinlich ist es besser, wenn Du die gesamte Prozedur in anderer Form in das KeyPress-Ereignis packst. Dort kannst Du nach jeder Tastatur-Eingabe, die Länge des enthaltenen Textes überprüfen und anhand dessen die Schrägstriche setzen.

VG
Carsten

Hallo Tobias.

Falls Interesse besteht: Ich habe als Ansatz mal ein wenig Code geschrieben. Er gehört in das KeyPress-Ereignis von txtAZ

 Select Case KeyAscii
 Case 48 To 57
 If Len(txtAZ.Text) = 3 Then
 txtAZ.Text = txtAZ.Text & "/"
 End If
 If Len(txtAZ.Text) \> 4 Then
 If InStr(1, txtAZ.Text, "9", vbTextCompare) = 5 Then
 txtAZ.MaxLength = 15
 If Len(txtAZ.Text) = 7 Then
 txtAZ.Text = txtAZ.Text & "/"
 End If
 If Len(txtAZ.Text) = 11 Then
 txtAZ.Text = txtAZ.Text & "/"
 End If
 Else
 txtAZ.MaxLength = 16
 If Len(txtAZ.Text) = 8 Then
 txtAZ.Text = txtAZ.Text & "/"
 End If
 If Len(txtAZ.Text) = 12 Then
 txtAZ.Text = txtAZ.Text & "/"
 End If
 End If
 End If
 txtAZ.SelStart = Len(txtAZ.Text)
 Case Else
 KeyAscii = 0
 Beep
 End Select

Eventuelle Korrekturen sind bisher noch nicht berücksichtigt, d.h. bei diesem Code muß der Anwender das Aktenzeichen korrekt eintippen. Es wird aber schon zwischen den beiden Formaten unterschieden.

VG
Carsten

1 Like

Hallo Carsten,

danke. Soweit klappt es. Ich guck noch die Feinheiten durch, aber das ist das kleinere Übel :smile:

LG Tobi@s

Hallo,

Hallo,

ich habe den Code jetzt soweit angepasst und möchte ihn für andere Neugierige veröffentlichen:

Der Code beinhaltet jetzt noch dass, wenn der Nutzer die Rücktaste drückt, das entsprechend letzte „/“ gleich mit gelöscht wird. Auch habe ich den Teil mit der Länge des Textfeldes weggelassen, da am Ende die Länge gleich ist, nur an 7./8. Stelle „vertauscht“ sich das setzen des „/“ wenn eine „9“ an 5. Stelle ist. Die entsprechende Prüfung habe ich nicht mit „Instr“ durchführen lassen, da bereits auch vorher eine „9“ im AZ enthalten sein kann (was du nicht wissen konntest).

Private Sub txtAZ_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
If KeyCode = 8 And Len(txtAZ.Text) > 3 Then
If Mid(txtAZ.Text, Len(txtAZ.Text) - 1, 1) = „/“ Then
txtAZ.Text = Left(txtAZ.Text, Len(txtAZ.Text) - 1)
End If
End If
End Sub

Private Sub txtAZ_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger)
'nur Zahlen erlaubt
Select Case KeyAscii
Case 48 To 57
If Len(txtAZ.Text) = 3 Then txtAZ.Text = txtAZ.Text & „/“
If Len(txtAZ.Text) = 12 Then txtAZ.Text = txtAZ.Text & „/“
If Mid(txtAZ.Text, 5, 1) = „9“ Then
If Len(txtAZ.Text) = 7 Then txtAZ.Text = txtAZ.Text & „/“
ElseIf Len(txtAZ.Text) = 8 Then
txtAZ.Text = txtAZ.Text & „/“
End If
txtAZ.SelStart = Len(txtAZ.Text)
Case Else
KeyAscii = 0
Beep
End Select
End Sub

Dankä

Hallo, Tobias.

Der Code beinhaltet jetzt noch dass, wenn der Nutzer die
Rücktaste drückt, das entsprechend letzte „/“ gleich mit
gelöscht wird.

Gute Idee!

Auch habe ich den Teil mit der Länge des
Textfeldes weggelassen, da am Ende die Länge gleich ist, nur
an 7./8. Stelle „vertauscht“ sich das setzen des „/“ wenn eine
„9“ an 5. Stelle ist. Die entsprechende Prüfung habe ich nicht
mit „Instr“ durchführen lassen, da bereits auch vorher eine
„9“ im AZ enthalten sein kann (was du nicht wissen konntest).

Daß beide Formate die gleiche Textlänge aufweisen, hab’ ich total übersehen. Das macht das Setzen der Maximallänge in der Tat überflüssig.

Was Du vielleicht noch berücksichtigen solltest, ist die Möglichkeit, daß der Anwender mit den Pfeiltasten durch den Text navigiert und an einer beliebigen Stelle sowohl mit Backspace (KeyCode 8) als auch mit Del (KeyCode 46) Zeichen löschen kann. Das bringt neue Probleme mit sich. Ich hab’ einfach noch 'mal etwas geschrieben, was die Problem zwar nicht vollstandig löst, aber doch eindämmt. Hier der Code:

Private Sub txtAZ\_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
 With txtAZ
 Select Case KeyCode
 Case 8 ' Taste Backspace
 If .SelStart = Len(.Text) Then
 If Len(.Text) \> 3 Then
 If Mid(.Text, Len(.Text) - 1, 1) = "/" Then
 .Text = Left(.Text, Len(.Text) - 1)
 End If
 End If
 Else
 If Mid(.Text, .SelStart, 1) = "/" Then
 KeyCode = 0
 Beep
 End If
 End If
 Case 46 'Taste Del
 If Mid(.Text, .SelStart + 1, 1) = "/" Then
 KeyCode = 0
 Beep
 End If
 End Select
 End With
End Sub

Private Sub txtAZ\_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger)
'Format 1: xxx/xxxx/xxx/xxx
'Format 2: xxx/9xx/xxxx/xxx
 With txtAZ
 Select Case KeyAscii
 Case 48 To 57
 If .SelStart = Len(.Text) Then
 If Len(.Text) = 3 Then .Text = .Text & "/"
 If Len(.Text) = 12 Then .Text = .Text & "/"
 If Mid(.Text, 5, 1) = "9" Then
 If Len(.Text) = 7 Then .Text = .Text & "/"
 Else
 If Len(.Text) = 8 Then .Text = .Text & "/"
 End If
 .SelStart = Len(.Text)
 Else
 If .SelStart = 4 Then
 Select Case KeyAscii
 Case 57 '9
 .Text = Left(.Text, 4) & Chr(KeyAscii) & Mid(.Text, 5, 2) & "/" & Mid(.Text, 7, 1) & Mid(.Text, 9, 7)
 Case Else
 .Text = Left(.Text, 4) & Chr(KeyAscii) & Mid(.Text, 5, 2) & Mid(.Text, 8, 1) & "/" & Mid(.Text, 9, 7)
 End Select
 .SelStart = 5
 End If
 End If
 Case Else
 KeyAscii = 0
 Beep
 End Select
 End With
End Sub

Der Code im KeyDown-Ereignis macht Folgendes:
Wenn der Benutzer die Taste Backspace oder Del drückt und sich die Einfügemarke vor oder hinter einem Schrägstrich befindet, wird KeyCode auf 0 gesetzt, sodaß die Schrägstriche nicht gelöscht werden können, es sei denn, die Einfügemarke befindet sich am Ende des Textes.

Der Code im KeyPress-Ereignis macht Folgendes:

Das automatische Einfügen der Schrägstriche wird nur dann ausgeführt, wenn sich die Einfügemarke am Ende des Textes befindet. Das hat den Vorteil, daß Änderungen an anderer Stelle im Text auch an eben dieser Stelle gemacht werden.
Wenn der Anwender die Einfügemarke hinter den 1. Schrägstrich setzt und das 5. Zeichen ersetzt, wird in Abhängigkeit des eingegebenen Zeichens das Format geändert. Das funktioniert aber nur, wenn ansonsten die Zeichenfolge komplett ist.

Vielleicht hast Du ja Lust, den Code 'mal auszuprobieren. Aber wie gesagt: Er löst nicht alle Probleme.

VG
Carsten

1 Like

Textfeld, TextBox bei Eingabe automat. formatieren
Hallo Carsten, Tobias,

ich habe jetzt den neuen Code von Carsten noch nicht getestet.
Und ja, so einfach ist das Problem nicht zu lösen.
_Change scheidet aus, irgendwie untauglich.
Ich mutmaße stark daß eine perfekte Lösung sofern es sie überhaupt geben kann aus einer Mischung aus
_KeyDown und _keyPress bestehen wird.

Bei den ersten Codes sah ich das Problem, was ja auch jetzt von Carsten gesagt wurde daß ein User ja mit den Pfeiltasten zurückwandern könnte und dann so einen Slash löschen.
Dann hat er keine Chance den wieder einzugeben außer er löscht fast alles und fängt wieder von vorne an.

Ähnlich problematisch sah ich auch in weiteren Codes daß ein User es nicht schaffen kann wenn er feststellt, oh da „vorne“ sollte die 2 eine 3 sein.
Er kann wohl die 2 löschen und bleibt auch mit dem Cursor an der Stelle stehen, aber tippselt er eine 3 ein so wird sie „hinten“ an die TB angehängt.

Ich habe dann zwischenzeitlich einen völlig anderen Ansatz versucht. So wie man bei MS-Produkten da dieses Serial-ID des Produkts in einige Textboxen eingeben kann, so wäre dieses Vorgehen vielleicht auch brauchbar.
Muß aber Tobias entscheiden ob das in Frage käme.
(Beim Testen sah ich auch da Schwieigkeiten :frowning: )

Zurück zur Keypress, Keydown-Methode.
Nachfolgend mein aktueller Codeversuch.
Alles noch Baustelle wie die Codes davor.
Aber vielleicht als Grundansatz brauchbar.
Das mit der 9 fehlt noch vollkommen, hat aber auch für mich keine priorität, wenn der Code funktioniert wird es wohl leicht sein das noch einzubauen.
Wenn nicht, *Schulterzuck*, dann habe ich das wohl falsch eingeschätzt :smile:)

Gruß
Reinhard

In Modul des Blattes:

Private Sub txtAZ\_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
'[A1] = KeyCode
Select Case KeyCode
 Case 48 To 57
 Case 8, 13, 16, 35, 36, 37, 39, 46
Case Else
 KeyCode = 0
 Beep
 Exit Sub
End Select
txtAZ.Text = Pruef(txtAZ.Text)
End Sub

Private Sub txtAZ\_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger)
If KeyAscii = 47 Then
 KeyAscii = 0
 Beep
End If
End Sub

In Modul1 o.ä.:

Function Pruef(ByVal strTB As String) As String
Dim T As Integer
strTB = Replace(strTB, "/", "")
For T = 1 To Len(strTB)
 Pruef = Pruef & Mid(strTB, T, 1)
 If T = 3 Or T = 7 Or T = 10 Then Pruef = Pruef & "/"
Next T
[a2] = Len(Pruef)
'If Len(Pruef) \> 16 Then
' Beep
 Pruef = Left(Pruef, 16)
'End If
End Function

Neueste Version: maskiertes Textfeld
Hallo Tobias.

Ich habe jetzt eine Version geschrieben, die meines Erachtens alle Probleme löst.

Voraussetzung dafür ist allerdings, dass die Eingabemaske, die Du in Deinem Eröffnungs-Posting erwähnt hast, ein UserForm ist.

Um dieses Beispiel auszuprobieren, benötigst Du folgende „Bauteile“:

Einen CommandButton auf dem Word-Dokument oder im Ribbon-Menü.
Ein UserForm mit dem Namen „frmAZ“, und darauf eine TextBox mit dem Namen „txtAZ“.
Ein Modul.
Ein Klassenmodul mit dem Namen „AZ“

Folgender Code gehört in das Click-Ereignis des CommandButtons:

Call ShowAktenzeichen

Folgender Code gehört in das Codefenster des Moduls:

Public Sub ShowAktenzeichen()
 Dim nf As New frmAZ
 nf.Show vbModal
End Sub

Folgender Code gehört in das Codefenster des UserForm:

Private Aktenzeichen As New AZ

Private Sub txtAZ\_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
 Select Case KeyCode
 Case 8, 27, 46 'Backspace,Escape,Del
 Dim Key As Integer
 Key = KeyCode
 KeyCode = 0
 txtAZ.Text = Aktenzeichen.Update(txtAZ.Text, txtAZ.SelStart, Key)
 txtAZ.SelStart = Aktenzeichen.SelStart
 End Select
End Sub

Private Sub txtAZ\_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger)
 Select Case KeyAscii
 Case 48 To 57 '0 bis 9
 Dim Key As Integer
 Key = KeyAscii
 KeyAscii = 0
 txtAZ.Text = Aktenzeichen.Update(txtAZ.Text, txtAZ.SelStart, Key)
 txtAZ.SelStart = Aktenzeichen.SelStart
 Case Else
 KeyAscii = 0
 Beep
 End Select
End Sub

Private Sub UserForm\_Initialize()
 Aktenzeichen.SelectedFormatIndex = F2
 txtAZ.Text = Aktenzeichen.SelectedFormat(Aktenzeichen.SelectedFormatIndex)
 txtAZ.SelStart = Aktenzeichen.SelStart
End Sub

Folgender Code gehört in das Codefenster des Klassenmoduls:

Option Explicit
Private Const myFormat1 As String = "---/----/---/---"
Private Const myFormat2 As String = "---/9--/----/---"
Private Const myPlaceHolder As String = "-"
Private Const myGroupSeperator As String = "/"
Private myFormats(7 To 8) As String
Private mySelectedFormatIndex As Integer
Private mySelStart As Integer
Public Enum FormatSelection
 F2 = 7
 F1
End Enum

Public Property Get SelectedFormat(ByVal Index As FormatSelection) As String
 SelectedFormat = myFormats(Index)
End Property

Public Property Get Format1() As String
 Format1 = myFormat1
End Property

Public Property Get Format2() As String
 Format2 = myFormat2
End Property

Public Property Get SelectedFormatIndex() As FormatSelection
 SelectedFormatIndex = mySelectedFormatIndex
End Property

Public Property Let SelectedFormatIndex(ByVal sf As FormatSelection)
 mySelectedFormatIndex = sf
End Property

Public Property Get SelStart() As Integer
 SelStart = mySelStart
End Property

Public Function Update(ByVal Text As String, ByVal SelStart As Integer, ByVal Key As Integer) As String
 On Error GoTo ErrHandler
 Dim NewText As String
 
 Select Case Key
 Case 48 To 57 '0 bis neun
 GoSub SplitChars
 GoTo KeyPressed
 Case 8, 46 'Backspace,Del
 GoSub SplitChars
 GoTo KeyDowned
 Case 27 ' Escape
 NewText = myFormats(mySelectedFormatIndex)
 mySelStart = 0
 GoTo Finally
 Case Else
 NewText = Text
 GoTo Finally
 End Select


SplitChars:
 Dim Chars() As String
 Dim i As Integer
 ReDim Chars(1 To Len(Text))
 For i = LBound(Chars, 1) To UBound(Chars, 1)
 Chars(i) = Mid(Text, i, 1)
 Next
Return

KeyPressed:
 Select Case SelStart
 Case 0 To 3, 5 To 15
 Chars(SelStart + 1) = Chr(Key)
 Case 4
 Select Case Key
 Case 57 '9
 If mySelectedFormatIndex = FormatSelection.F1 Then
 Chars(9) = Chars(8)
 Chars(8) = myGroupSeperator
 End If
 mySelectedFormatIndex = FormatSelection.F2
 Case Else
 If mySelectedFormatIndex = FormatSelection.F2 Then
 Chars(8) = Chars(9)
 Chars(9) = myGroupSeperator
 End If
 mySelectedFormatIndex = FormatSelection.F1
 End Select
 Chars(SelStart + 1) = Chr(Key)
 End Select
 mySelStart = SelStart + 1
 If mySelStart = 3 Then mySelStart = mySelStart + 1
 If mySelStart = mySelectedFormatIndex Then mySelStart = mySelStart + 1
 If mySelStart = 12 Then mySelStart = mySelStart + 1
 GoTo JoinChars

KeyDowned:
 Select Case Key
 Case 8
 If Chars(SelStart) = myGroupSeperator Then SelStart = SelStart - 1
 Chars(SelStart) = myPlaceHolder
 mySelStart = SelStart - 1
 Case 46
 If Chars(SelStart + 1) = myGroupSeperator Then SelStart = SelStart + 1
 Chars(SelStart + 1) = myPlaceHolder
 mySelStart = SelStart + 1
 End Select


JoinChars:
 For i = LBound(Chars, 1) To UBound(Chars, 1)
 NewText = NewText & Chars(i)
 Next

Finally:
 Update = NewText
 Exit Function

ErrHandler:
 NewText = myFormat1
 Resume Finally
End Function

Private Sub Class\_Initialize()
 mySelectedFormatIndex = FormatSelection.F1
 myFormats(FormatSelection.F1) = myFormat1
 myFormats(FormatSelection.F2) = myFormat2
End Sub

Ich lasse den Code an dieser Stelle erst einmal völlig unerklärt, da ich ja nicht weiß, ob überhaupt noch Interesse besteht. Ich finde, die Funktionalität durchaus gelungen.

VG
Carsten

Hallo Carsten

ich werde mir den Code auf alle Fälle ansehen, vielleicht kapier ich dann wie „Klassenprogrammierung“ funktioniert :smile:
Nur muss ich schauen dass ich dieses programmieren neben meiner normalen Arbeit mache; muss gucken wann ich dazu komme :smile:

LG und Danke
Tobi@s