Hi,
ich habe in den letzten Tagen eine kleine UDF zusammengebastelt, mit der man einen Filter für ein Input (oder Edit) festlegen kann. So muss die Eingabe nicht im Nachhinein überprüft werden, denn der User hat gar nicht erst die Möglichkeit, eine ungültige Eingabe zu machen.
Eine ähnliche UDF (Thread im EN-Forum) hat der liebe peethebee schon mal geschrieben, allerdings habe ich einen geringfügig anderen Ansatz gewählt.
Die übliche Methode für so etwas führt über GUIRegisterMsg, um so die Nachricht EN_CHANGE abzufangen und ggf. den Inhalt des Inputs wieder zurück zu ändern. Dies erschien mir ein wenig ineffektiv, da man eine bereits vorgenommene Änderung wieder rückgängig macht. Daher habe ich einfach die WndProc des eigentlichen Edit-Controls ersetzt und fange dort bereits die Nachricht WM_CHAR ab. So findet die Änderung des Inhalts bei unzulässigen Zeichen gar nicht erst statt.
Ein weiterer Vorteil meiner Methode besteht in der Nutzung von SetWindowLong: Im selben Skript kann eine eigene GUIRegisterMsg-Funktion ohne jegliche Einschränkung genutzt werden, es sind keinerlei Anpassungen nötig.
Der wahrscheinlich größte Vorteil meiner UDF liegt allerdings in den logischen Möglichkeiten, wenn man es so nennen möchte. Wo sich andere UDFs oder Funktionen nur auf bestimmte definierte Zeichen oder reguläre Ausdrücke verlassen, wird hier einfach eine Art Entscheidungs-Funktion angegeben, in der die Logik frei programmiert werden kann. Diese Technik garantiert das höchste Maß an Flexibilität. Diese Filter-Funktion wird dann bei jedem relevanten Tastendruck mit zwei Parametern aufgerufen: Das erzeugte Zeichen und der resultierende Gesamtstring. Über den Rückgabewert wird dann bestimmt, ob das Zeichen zulässig ist oder nicht. Ganz einfach und flexibel.
Dazu gibt es - praktisch als kleine Spielerei - für den Benutzer ein optisches Feedback bei ungültigen Eingaben:
Wie man sieht, ähnelt das Ganze ein wenig dem Style ES_NUMBER.
Ich habe auch ein kleines Beispielskript, an dem vielleicht das ein oder andere nochmal veranschaulicht wird:
InputFilter Example.au3
#include "InputFilter.au3"$hMainWnd = GUICreate("InputFilter Example", 200, 30)$cInput = GUICtrlCreateInput("", 0, 0, 200, 30)GUICtrlSetFont($cInput, 15)GUICtrlInputSetFilter($cInput, "InputFilter")GUISetState()While True Switch GUIGetMsg() Case -3 Exit EndSwitchWEndFunc InputFilter($sChr, $sStr) If StringRegExp($sStr, "^\+?(\d{2,4} )?(\d{3} )?\d*$") Then Return $INPUTFILTER_ALLOW ;Simple Handynummer If StringInStr(@CRLF, $sChr) Then Return $INPUTFILTER_SILENTDENY ;"Enter" ist gleichzeitig eine Bestätigung, dabei nervt die Benachrichtigung nur Return $INPUTFILTER_DENYEndFunc ;==>InputFilter
[/autoit]Wie schon erwähnt, wird die Filter-Funktion mit zwei Parametern aufgerufen:
- Char: Das eingegebene Zeichen
- String: Der String, der theoretisch im Input stehen würde.
Die Gültigkeit einer Eingabe wird dann über drei Konstanten als Rückgabewert der Filterfunktion geregelt:
- $INPUTFILTER_ALLOW: Das Zeichen ist gültig.
- $INPUTFILTER_DENY: Das Zeichen ist ungültig, der Benutzer erhält eine optische Rückmeldung.
- $INPUTFILTER_SILENTDENY: Das Zeichen ist ungültig, der Benutzer erhält keine optische Rückmeldung.
Update :: Version 1.1
Raupi meinte, dass für Anfänger das Konzept einer Callback-Funktion zu kompliziert sein könnte. Daher habe ich die UDF so erweitert, dass 4 vordefinierte Filtermethoden zur Verfügung stehen. Die Callback-Funktion ist dann die 5. Möglichkeit.
-
Whitelist ($INPUTFILTER_WHITELIST)
Bei jedem Tastendruck wird überprüft, ob das entstehende Zeichen im Filter-String steht. Wenn ja, dann wird er zugelassen.Beispiel: Filter-String "ABC" - Es dürfen nur die drei Zeichen "ABC" eingegeben werden. -
Blacklist ($INPUTFILTER_BLACKLIST)
Bei jedem Tastendruck wird überprüft, ob das entstehende Zeichen im Filter-String steht. Wenn nein, dann wird er zugelassen.Beispiel: Filter-String "ABC" - Es dürfen alle Zeichen außer "ABC" eingegeben werden. -
RegExp ($INPUTFILTER_REGEXP)
Bei jedem Tastendruck wird überprüft, ob das entstehende Zeichen einen RegExp-Match bei dem Filter-String als Pattern erzeugt. Wenn ja, dann wird er zugelassen.Beispiel: Filter-String "[A-C]" - Es dürfen nur die drei Zeichen "ABC" eingegeben werden. -
RegExp All ($INPUTFILTER_REGEXP_ALL)
Bei jedem Tastendruck wird überprüft, ob der entstehende String einen RegExp-Match bei dem Filter-String als Pattern erzeugt. Wenn ja, dann wird er zugelassen.
Die Konstante in den Klammern übergibt man zur Auswahl der Arbeitsweise einfach als dritten Parameter an GUICtrlInputSetFilter. Wenn der dritte Parameter weggelassen wird, wird automatisch $INPUTFILTER_CALLBACK genutzt. Der Filter-String fungiert dann wie oben beschrieben als Filter-Funktion, es handelt sich also nicht um ein Script-Breaking-Change.
Beispiel (Handynummer-Beispiel von oben):
GUICtrlInputSetFilter($cInput, "^\+?(\d{2,4} )?(\d{3} )?\d{0,8}$", $INPUTFILTER_REGEXP_ALL)
Wer sich noch für das Interne interessiert: Die Verwaltung der fensterbezogenen Daten erfolgt nicht über ein globales Array o.Ä., sondern über das USERDATA-Feld in der Fenstertabelle. Das ist dann im direkten Vergleich mit einem globalen Array "übersauber".
Damit sollte die UDF eigentlich benutzbar sein. Die einzige Funktion (GUICtrlInputSetFilter) sollte wohl selbsterklärend sein. Wenn nicht, dann liegt im angehängten ZIP-Archiv eine Kurzdokumentation im HTML-Format bei. Die UDF selber unterliegt nebenbei der GPLv3, ist auch im Header angemerkt.
Lob und Kritik sind natürlich immer gern gesehen, solange letzteres konstruktiv ist.
Gruß,
chess