Sehr alter Thread, aber dieser scheint ordentlicher zu sein und entfernt nicht numerische Zeichen, wenn er eingefügt wird.
// force the field to be numeric only
textField.textProperty().addListener(newChangeListener<String>(){@Overridepublicvoid changed(ObservableValue<?extendsString> observable,String oldValue,String newValue){if(!newValue.matches("\\d*")){
textField.setText(newValue.replaceAll("[^\\d]",""));}}});
Funktioniert wunderbar. Beachten Sie, dass Sie stattdessen auch \\D+(oder nur \\D) anstelle von verwenden können [^\\d], wenn Sie einige Zeichen speichern möchten.
Ricky3350
5
Noch einfacher ist es, den Text auf oldValue zurückzusetzen. Auf diese Weise müssen Sie nicht mit Regex-Ersetzungen herumspielen (was bei mir leider überhaupt nicht funktioniert hat).
geisterfurz007
@ geisterfurz007 Dies gibt jedoch die Möglichkeit, nicht numerische Zeichen aus eingefügtem Text zu entfernen.
Evan Knowles
10
Veraltet, siehe TextFormatter-Antwort unten.
Gerardw
3
Könnte auch möglicherweise nur verwenden Integer.parseInt(newValue)und verwenden tryund catcheinen Fehler aufNumberFormatException
Pixel
43
Update Apr 2016
Diese Antwort wurde vor einigen Jahren erstellt und die ursprüngliche Antwort ist jetzt weitgehend veraltet.
Seit Java 8u40 verfügt Java über einen TextFormatter, der normalerweise am besten geeignet ist, um die Eingabe bestimmter Formate wie z. B. Zahlen in JavaFX TextFields zu erzwingen:
Siehe auch andere Antworten auf diese Frage, in denen TextFormatter ausdrücklich erwähnt wird.
Ursprüngliche Antwort
Es gibt einige Beispiele dafür in diesem Kern , ich habe eines der folgenden Beispiele dupliziert:
// helper text field subclass which restricts text input to a given range of natural int numbers// and exposes the current numeric int value of the edit box as a value property.classIntFieldextendsTextField{finalprivateIntegerProperty value;finalprivateint minValue;finalprivateint maxValue;// expose an integer value property for the text field.publicint getValue(){return value.getValue();}publicvoid setValue(int newValue){ value.setValue(newValue);}publicIntegerProperty valueProperty(){return value;}IntField(int minValue,int maxValue,int initialValue){if(minValue > maxValue)thrownewIllegalArgumentException("IntField min value "+ minValue +" greater than max value "+ maxValue
);if(maxValue < minValue)thrownewIllegalArgumentException("IntField max value "+ minValue +" less than min value "+ maxValue
);if(!((minValue <= initialValue)&&(initialValue <= maxValue)))thrownewIllegalArgumentException("IntField initialValue "+ initialValue +" not between "+ minValue +" and "+ maxValue
);// initialize the field values.this.minValue = minValue;this.maxValue = maxValue;
value =newSimpleIntegerProperty(initialValue);
setText(initialValue +"");finalIntField intField =this;// make sure the value property is clamped to the required range// and update the field's text to be in sync with the value.
value.addListener(newChangeListener<Number>(){@Overridepublicvoid changed(ObservableValue<?extendsNumber> observableValue,Number oldValue,Number newValue){if(newValue ==null){
intField.setText("");}else{if(newValue.intValue()< intField.minValue){
value.setValue(intField.minValue);return;}if(newValue.intValue()> intField.maxValue){
value.setValue(intField.maxValue);return;}if(newValue.intValue()==0&&(textProperty().get()==null||"".equals(textProperty().get()))){// no action required, text property is already blank, we don't need to set it to 0.}else{
intField.setText(newValue.toString());}}}});// restrict key input to numerals.this.addEventFilter(KeyEvent.KEY_TYPED,newEventHandler<KeyEvent>(){@Overridepublicvoid handle(KeyEvent keyEvent){if(intField.minValue<0){if(!"-0123456789".contains(keyEvent.getCharacter())){
keyEvent.consume();}}else{if(!"0123456789".contains(keyEvent.getCharacter())){
keyEvent.consume();}}}});// ensure any entered values lie inside the required range.this.textProperty().addListener(newChangeListener<String>(){@Overridepublicvoid changed(ObservableValue<?extendsString> observableValue,String oldValue,String newValue){if(newValue ==null||"".equals(newValue)||(intField.minValue<0&&"-".equals(newValue))){
value.setValue(0);return;}finalint intValue =Integer.parseInt(newValue);if(intField.minValue > intValue || intValue > intField.maxValue){
textProperty().setValue(oldValue);}
value.set(Integer.parseInt(textProperty().get()));}});}}
Weiß jemand, welcher Regex für Dezimalzahlen verwendet werden soll (z. B. 123.456)? Der Wert des Validierungsfunktionsparameters "Text" (Text) ist das zuletzt vom Benutzer bearbeitete Zeichen, nicht die gesamte Zeichenfolge im Textfeld. Daher stimmt der reguläre Ausdruck möglicherweise nicht richtig überein. Zum Beispiel benutze ich diesen Befehl wie text.matches("\\d+");
Ich denke, dass dies eine gute Lösung ist, aber ich würde eines ändern. Anstatt text.matches ("[0-9] *") zu schreiben, würde ich eine Variable für das Muster erstellen und es kompilieren. In Ihrem Code wird das Muster jedes Mal kompiliert, wenn jemand ein Zeichen in ein Feld schreibt, was für CPU und Speicher kostspielig ist. Also würde ich eine Variable hinzufügen: private static Pattern integerPattern = Pattern.compile ("[0-9] *"); Und ersetzen Sie validate body durch: integerPattern.matcher (text) .matches ();
P. Jowko
37
Ab JavaFX 8u40 können Sie ein TextFormatter-Objekt für ein Textfeld festlegen:
Dadurch werden sowohl Unterklassen- als auch doppelte Änderungsereignisse vermieden, die Sie erhalten, wenn Sie der Texteigenschaft einen Änderungslistener hinzufügen und den Text in diesem Listener ändern.
Das TextInputhat ein TextFormatter, mit dem die eingegebenen Textarten formatiert, konvertiert und begrenzt werden können.
Das TextFormatterhat einen Filter, mit dem Eingaben verworfen werden können. Wir müssen dies festlegen, um alles abzulehnen, was keine gültige Ganzzahl ist. Es gibt auch einen Konverter, den wir einstellen müssen, um den Zeichenfolgenwert in einen ganzzahligen Wert zu konvertieren, den wir später binden können.
Erstellen wir einen wiederverwendbaren Filter:
publicclassIntegerFilterimplementsUnaryOperator<TextFormatter.Change>{privatefinalstaticPattern DIGIT_PATTERN =Pattern.compile("\\d*");@OverridepublicChange apply(TextFormatter.Change aT){return DIGIT_PATTERN.matcher(aT.getText()).matches()? aT :null;}}
Der Filter kann eines von drei Dingen ausführen: Er kann die Änderung unverändert zurückgeben, um sie so zu akzeptieren, wie sie ist, er kann die Änderung auf eine Weise ändern, die er für geeignet hält, oder er kann zurückkehren null, um die Änderung insgesamt abzulehnen.
manchmal hast du eine ausnahme, weil der nuber zu groß sein könnte.
schlagi123
1
Tipp: Ersetzen Sie den regulären Ausdruck "\\ d +" durch "\\ d *". Auf diese Weise können Sie alle Zeichen aus dem Texteingabefeld entfernen (verwenden Sie die Rücktaste / Löschen, um das Feld zu löschen).
Guus
1
Vergessen Sie nicht, die Caret-Position einzustellen, nachdem Sie sie auf den alten Wert zurückgesetzt haben:textField.positionCaret(textField.getLength());
Hsson
Ändern Sie die Faust-if-Bedingung in: if (newValue.matches("\\d*") && newValue.getText().length < 5) Wenn Sie die Eingabe in diesem Fall auf 4 Stellen beschränken möchten.
Cappuccino90
@ Cappuccino90 Sie sollten die Anweisungen wechseln, da die Längenprüfung bei jedem Treffer viel billiger ist als das Parsen eines
regulären Ausdrucks
9
Ab Java SE 8u40 können Sie für diesen Bedarf eine " Ganzzahl " verwenden Spinner, mit der Sie eine gültige Ganzzahl sicher auswählen können, indem Sie die Aufwärtspfeil- / Abwärtspfeiltasten der Tastatur oder die mit den Aufwärtspfeil- / Abwärtspfeil-Tasten verwenden.
Sie können auch einen Min- , einen Max- und einen Anfangswert definieren, um die zulässigen Werte und einen Betrag zu begrenzen, um den pro Schritt erhöht oder verringert werden soll.
Beispielsweise
// Creates an integer spinner with 1 as min, 10 as max and 2 as initial valueSpinner<Integer> spinner1 =newSpinner<>(1,10,2);// Creates an integer spinner with 0 as min, 100 as max and 10 as initial // value and 10 as amount to increment or decrement by, per stepSpinner<Integer> spinner2 =newSpinner<>(0,100,10,10);
Beispiel eines Ergebnisses mit einem " Integer " -Spinner und einem " Double " -Spinner
Ein Drehfeld ist ein einzeiliges Textfeldsteuerelement, mit dem der Benutzer eine Zahl oder einen Objektwert aus einer geordneten Folge solcher Werte auswählen kann. Spinner bieten normalerweise ein Paar winziger Pfeiltasten zum Durchlaufen der Elemente der Sequenz. Die Aufwärtspfeil- / Abwärtspfeiltasten der Tastatur durchlaufen ebenfalls die Elemente. Dem Benutzer kann auch gestattet werden, einen (legalen) Wert direkt in den Spinner einzugeben. Obwohl Kombinationsfelder ähnliche Funktionen bieten, werden Spinner manchmal bevorzugt, weil sie keine Dropdown-Liste benötigen, die wichtige Daten verdecken kann, und weil sie Funktionen wie das Umbrechen vom Maximalwert zurück zum Minimalwert ermöglichen (z. von der größten positiven ganzen Zahl bis 0).
Die ifKlausel ist wichtig, um Eingaben wie 0.5d oder 0.7f zu verarbeiten, die von Int.parseInt () korrekt analysiert werden, aber nicht im Textfeld erscheinen sollten.
Woot? Seit wann wird 0.5d von Integer.parseInt () korrekt analysiert?! Es löst eine java.lang.NumberFormatException aus: Für Eingabezeichenfolge: "0.5d" (wie erwartet, da es sich nicht um eine Ganzzahl handelt)
Burkhard
6
Die bevorzugte Antwort kann noch kleiner sein, wenn Sie Java 1.8 Lambdas verwenden
Mit dieser Methode kann TextField die gesamte Verarbeitung abschließen (Kopieren / Einfügen / Rückgängig machen). Es ist nicht erforderlich, Klassen zu erweitern, und Sie können nach jeder Änderung entscheiden, was mit neuem Text geschehen soll (um ihn auf Logik zu verschieben, zum vorherigen Wert zurückzukehren oder ihn sogar zu ändern).
// fired by every text property change
textField.textProperty().addListener((observable, oldValue, newValue)->{// Your validation rules, anything you like// (! note 1 !) make sure that empty string (newValue.equals("")) // or initial text is always valid// to prevent inifinity cycle// do whatever you want with newValue// If newValue is not valid for your rules((StringProperty)observable).setValue(oldValue);// (! note 2 !) do not bind textProperty (textProperty().bind(someProperty))// to anything in your code. TextProperty implementation// of StringProperty in TextFieldControl// will throw RuntimeException in this case on setValue(string) call.// Or catch and handle this exception.// If you want to change something in text// When it is valid for you with some changes that can be automated.// For example change it to upper case((StringProperty)observable).setValue(newValue.toUpperCase());});
Fügen Sie für Ihren Fall einfach diese Logik hinzu. Funktioniert perfekt.
if(newValue.equals(""))return;try{Integer i =Integer.valueOf(newValue);// do what you want with this i}catch(Exception e){((StringProperty)observable).setValue(oldValue);}
Mmmm. Ich bin vor Wochen auf dieses Problem gestoßen. Da die API keine Steuerung bietet, um dies zu erreichen,
möchten Sie möglicherweise eine eigene verwenden. Ich habe so etwas benutzt wie:
publicclassIntegerBoxextendsTextBox{public-init var value :Integer=0;protected function apply(){try{
value =Integer.parseInt(text);}catch(e :NumberFormatException){}
text ="{value}";}
override var focused =false on replace {apply()};
override var action = function (){apply()}}
Es wird genauso verwendet wie ein normales TextBox, hat
aber auch ein valueAttribut, das die eingegebene Ganzzahl speichert.
Wenn das Steuerelement den Fokus verliert, es bestätigt den Wert und kehrt es (wenn nicht gültig ist).
Dieser Code Lassen Sie Ihr Textfeld nur eine Nummer akzeptieren
textField.lengthProperty().addListener((observable, oldValue, newValue)->{if(newValue.intValue()> oldValue.intValue()){char c = textField.getText().charAt(oldValue.intValue());/** Check if the new character is the number or other's */if( c >'9'|| c <'0'){/** if it's not number then just setText to previous one */
textField.setText(textField.getText().substring(0,textField.getText().length()-1));}}});
Schlüsselwort synchronisiert wird hinzugefügt, um mögliche Probleme mit der Render-Sperre in javafx zu vermeiden, wenn setText aufgerufen wird, bevor die Ausführung des alten abgeschlossen ist. Es ist einfach zu reproduzieren, wenn Sie sehr schnell falsche Zeichen eingeben.
Ein weiterer Vorteil ist, dass Sie nur ein Muster beibehalten und nur einen Rollback durchführen. Es ist besser, weil Sie die Lösung für verschiedene Desinfektionsmuster leicht abstragieren können.
Antworten:
Sehr alter Thread, aber dieser scheint ordentlicher zu sein und entfernt nicht numerische Zeichen, wenn er eingefügt wird.
quelle
\\D+
(oder nur\\D
) anstelle von verwenden können[^\\d]
, wenn Sie einige Zeichen speichern möchten.Integer.parseInt(newValue)
und verwendentry
undcatch
einen Fehler aufNumberFormatException
Update Apr 2016
Diese Antwort wurde vor einigen Jahren erstellt und die ursprüngliche Antwort ist jetzt weitgehend veraltet.
Seit Java 8u40 verfügt Java über einen TextFormatter, der normalerweise am besten geeignet ist, um die Eingabe bestimmter Formate wie z. B. Zahlen in JavaFX TextFields zu erzwingen:
Siehe auch andere Antworten auf diese Frage, in denen TextFormatter ausdrücklich erwähnt wird.
Ursprüngliche Antwort
Es gibt einige Beispiele dafür in diesem Kern , ich habe eines der folgenden Beispiele dupliziert:
quelle
Ich weiß, dass dies ein ziemlich alter Thread ist, aber für zukünftige Leser ist hier eine andere Lösung, die ich ziemlich intuitiv fand:
Edit: Danke none_ und SCBoy für deine Verbesserungsvorschläge.
quelle
text.matches("\\d+");
Ab JavaFX 8u40 können Sie ein TextFormatter-Objekt für ein Textfeld festlegen:
Dadurch werden sowohl Unterklassen- als auch doppelte Änderungsereignisse vermieden, die Sie erhalten, wenn Sie der Texteigenschaft einen Änderungslistener hinzufügen und den Text in diesem Listener ändern.
quelle
Das
TextInput
hat einTextFormatter
, mit dem die eingegebenen Textarten formatiert, konvertiert und begrenzt werden können.Das
TextFormatter
hat einen Filter, mit dem Eingaben verworfen werden können. Wir müssen dies festlegen, um alles abzulehnen, was keine gültige Ganzzahl ist. Es gibt auch einen Konverter, den wir einstellen müssen, um den Zeichenfolgenwert in einen ganzzahligen Wert zu konvertieren, den wir später binden können.Erstellen wir einen wiederverwendbaren Filter:
Der Filter kann eines von drei Dingen ausführen: Er kann die Änderung unverändert zurückgeben, um sie so zu akzeptieren, wie sie ist, er kann die Änderung auf eine Weise ändern, die er für geeignet hält, oder er kann zurückkehren
null
, um die Änderung insgesamt abzulehnen.Wir werden den Standard
IntegerStringConverter
als Konverter verwenden.Alles zusammen haben wir:
Wenn Sie keinen wiederverwendbaren Filter benötigen, können Sie stattdessen diesen ausgefallenen Einzeiler verwenden:
quelle
Ich mag keine Ausnahmen, deshalb habe ich die
matches
Funktion von String-Class verwendetquelle
textField.positionCaret(textField.getLength());
if (newValue.matches("\\d*") && newValue.getText().length < 5)
Wenn Sie die Eingabe in diesem Fall auf 4 Stellen beschränken möchten.Ab Java SE 8u40 können Sie für diesen Bedarf eine " Ganzzahl " verwenden
Spinner
, mit der Sie eine gültige Ganzzahl sicher auswählen können, indem Sie die Aufwärtspfeil- / Abwärtspfeiltasten der Tastatur oder die mit den Aufwärtspfeil- / Abwärtspfeil-Tasten verwenden.Sie können auch einen Min- , einen Max- und einen Anfangswert definieren, um die zulässigen Werte und einen Betrag zu begrenzen, um den pro Schritt erhöht oder verringert werden soll.
Beispielsweise
Beispiel eines Ergebnisses mit einem " Integer " -Spinner und einem " Double " -Spinner
Weitere Details zur Spinner-Steuerung
quelle
Die
if
Klausel ist wichtig, um Eingaben wie 0.5d oder 0.7f zu verarbeiten, die von Int.parseInt () korrekt analysiert werden, aber nicht im Textfeld erscheinen sollten.quelle
Die bevorzugte Antwort kann noch kleiner sein, wenn Sie Java 1.8 Lambdas verwenden
quelle
Versuchen Sie diesen einfachen Code, der die Arbeit erledigt.
quelle
Wenn Sie denselben Listener auf mehr als ein TextField anwenden möchten, ist dies die einfachste Lösung:
quelle
Dieser hat für mich gearbeitet.
quelle
Ich möchte mit meiner Idee helfen, Evan Knowles Antwort mit
TextFormatter
JavaFX 8 zu kombinierenalso viel glück;) bleib ruhig und codiere java
quelle
Hier ist eine einfache Klasse, die einige grundlegende Validierungen
TextField
mit verarbeitetTextFormatter
JavaFX 8u40 behandeltBEARBEITEN:
(Code zu Floerns Kommentar hinzugefügt)
Sie können es so verwenden:
oder Sie können es in einer fxml-Datei instanziieren und auf ein customTextField mit den entsprechenden Eigenschaften anwenden.
app.fxml:
CustomTextField.class:
Code auf Github
quelle
Das benutze ich:
Das gleiche in der Lambda-Notation wäre:
quelle
Mit dieser Methode kann TextField die gesamte Verarbeitung abschließen (Kopieren / Einfügen / Rückgängig machen). Es ist nicht erforderlich, Klassen zu erweitern, und Sie können nach jeder Änderung entscheiden, was mit neuem Text geschehen soll (um ihn auf Logik zu verschieben, zum vorherigen Wert zurückzukehren oder ihn sogar zu ändern).
Fügen Sie für Ihren Fall einfach diese Logik hinzu. Funktioniert perfekt.
quelle
Mmmm. Ich bin vor Wochen auf dieses Problem gestoßen. Da die API keine Steuerung bietet, um dies zu erreichen,
möchten Sie möglicherweise eine eigene verwenden. Ich habe so etwas benutzt wie:
Es wird genauso verwendet wie ein normales
TextBox
, hataber auch ein
value
Attribut, das die eingegebene Ganzzahl speichert.Wenn das Steuerelement den Fokus verliert, es bestätigt den Wert und kehrt es (wenn nicht gültig ist).
quelle
Dieser Code Lassen Sie Ihr Textfeld nur eine Nummer akzeptieren
quelle
Dieser Code funktioniert auch dann gut, wenn Sie versuchen, ihn zu kopieren / einzufügen.
quelle
In den letzten Aktualisierungen von JavaFX müssen Sie neuen Text in der Platform.runLater-Methode wie folgt festlegen:
Es ist eine gute Idee, auch die Caret-Position festzulegen.
quelle
Platform.runLater
erforderlich ist?Ich möchte Evan Knowles Antwort verbessern: https://stackoverflow.com/a/30796829/2628125
In meinem Fall hatte ich eine Klasse mit Handlern für den UI-Komponententeil. Initialisierung:
Und die numbericSanitization-Methode:
Schlüsselwort synchronisiert wird hinzugefügt, um mögliche Probleme mit der Render-Sperre in javafx zu vermeiden, wenn setText aufgerufen wird, bevor die Ausführung des alten abgeschlossen ist. Es ist einfach zu reproduzieren, wenn Sie sehr schnell falsche Zeichen eingeben.
Ein weiterer Vorteil ist, dass Sie nur ein Muster beibehalten und nur einen Rollback durchführen. Es ist besser, weil Sie die Lösung für verschiedene Desinfektionsmuster leicht abstragieren können.
quelle
Dies funktioniert einwandfrei, da Sie nur einen ganzzahligen Wert und einen Dezimalwert eingeben können (mit ASCII-Code 46).
quelle