Bardzo stary wątek, ale wydaje się schludniejszy i po wklejeniu usuwa znaki nienumeryczne.
// force the field to be numeric only
textField.textProperty().addListener(new ChangeListener<String>() {
@Overridepublicvoidchanged(ObservableValue<? extends String> observable, String oldValue,
String newValue){
if (!newValue.matches("\\d*")) {
textField.setText(newValue.replaceAll("[^\\d]", ""));
}
}
});
Działa wspaniale. Zauważ, że możesz także użyć \\D+(lub po prostu \\D) zamiast [^\\d], jeśli chcesz zaoszczędzić kilka znaków.
ricky3350
5
Jeszcze prostsze jest ustawienie tekstu z powrotem na oldValue. W ten sposób nie musisz majstrować przy zamianach wyrażeń regularnych (co niestety w ogóle nie działało).
geisterfurz007
@ geisterfurz007 Daje to jednak możliwość usunięcia wartości nienumerycznych z wklejonego tekstu.
Evan Knowles,
10
Nieaktualny, zobacz odpowiedź TextFormatter poniżej.
gerardw
3
Może też po prostu użyć Integer.parseInt(newValue)i użyć tryi catchwykryć błąd naNumberFormatException
Pixel
43
Aktualizacja kwiecień 2016 r
Ta odpowiedź powstała kilka lat temu, a pierwotna odpowiedź jest obecnie w dużej mierze przestarzała.
Od wersji Java 8u40 Java ma TextFormatter, który zwykle najlepiej nadaje się do wymuszania wprowadzania określonych formatów, takich jak liczby, w polach tekstowych JavaFX:
Zobacz także inne odpowiedzi na to pytanie, które wyraźnie wspominają o TextFormatter.
Oryginalna odpowiedź
W tym tekście jest kilka przykładów , powieliłem jeden z poniższych przykładów:
// 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{
finalprivate IntegerProperty value;
finalprivateint minValue;
finalprivateint maxValue;
// expose an integer value property for the text field.publicintgetValue(){ return value.getValue(); }
publicvoidsetValue(int newValue){ value.setValue(newValue); }
public IntegerProperty valueProperty(){ return value; }
IntField(int minValue, int maxValue, int initialValue) {
if (minValue > maxValue)
thrownew IllegalArgumentException(
"IntField min value " + minValue + " greater than max value " + maxValue
);
if (maxValue < minValue)
thrownew IllegalArgumentException(
"IntField max value " + minValue + " less than min value " + maxValue
);
if (!((minValue <= initialValue) && (initialValue <= maxValue)))
thrownew IllegalArgumentException(
"IntField initialValue " + initialValue + " not between " + minValue + " and " + maxValue
);
// initialize the field values.this.minValue = minValue;
this.maxValue = maxValue;
value = new SimpleIntegerProperty(initialValue);
setText(initialValue + "");
final IntField 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(new ChangeListener<Number>() {
@Overridepublicvoidchanged(ObservableValue<? extends Number> 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, new EventHandler<KeyEvent>() {
@Overridepublicvoidhandle(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(new ChangeListener<String>() {
@Overridepublicvoidchanged(ObservableValue<? extends String> 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()));
}
});
}
}
Czy ktoś wie, jakiego wyrażenia regularnego użyć dla liczb dziesiętnych (np. 123.456)? Wartość parametru funkcji validate (tekst) „tekst” jest ostatnim znakiem edytowanym przez użytkownika, a nie całym ciągiem znaków w polu tekstowym, dlatego wyrażenie regularne może nie być poprawnie dopasowane. Na przykład używam tego polecenia w ten sposób: text.matches("\\d+"); i nie mogę usunąć żadnych znaków z pola tekstowego
Myślę, że to dobre rozwiązanie, ale jedną rzecz bym zmienił. Zamiast pisać text.matches ("[0-9] *") stworzyłbym zmienną dla wzorca i skompilowałbym ją. W twoim kodzie wzorzec jest kompilowany za każdym razem, gdy ktoś pisze znak w polu, a to jest kosztowne dla procesora i pamięci. Więc dodałbym zmienną: private static Pattern integerPattern = Pattern.compile ("[0-9] *"); I zamień treść walidacji na: integerPattern.matcher (tekst) .matches ();
P. Jowko
38
Począwszy od JavaFX 8u40, można ustawić obiekt TextFormatter w polu tekstowym:
UnaryOperator<Change> filter = change -> {
String text = change.getText();
if (text.matches("[0-9]*")) {
return change;
}
returnnull;
};
TextFormatter<String> textFormatter = new TextFormatter<>(filter);
fieldNport = new TextField();
fieldNport.setTextFormatter(textFormatter);
Pozwala to uniknąć podklas i zduplikowanych zdarzeń zmiany, które otrzymasz, gdy dodasz odbiornik zmian do właściwości text i zmodyfikujesz tekst w tym detektorze.
TextInputMa TextFormatterktóre mogą być wykorzystane do formatu, konwersji i ograniczyć rodzaje tekstów, które mogą być wprowadzane.
TextFormatterPosiada filtr, który może być stosowany do odrzucenia wejście. Musimy ustawić tę opcję, aby odrzucić wszystko, co nie jest prawidłową liczbą całkowitą. Posiada również konwerter, który musimy ustawić, aby przekonwertować wartość ciągu na wartość całkowitą, którą możemy później powiązać.
Filtr może zrobić jedną z trzech rzeczy, może zwrócić niezmodyfikowaną zmianę, aby zaakceptować ją taką, jaka jest, może zmienić zmianę w sposób, który uzna za stosowny, lub może powrócić, nullaby odrzucić zmianę w całości.
TextField textField = ...;
TextFormatter<Integer> formatter = new TextFormatter<>(
new IntegerStringConverter(), // Standard converter form JavaFX
defaultValue,
new IntegerFilter());
formatter.valueProperty().bindBidirectional(myIntegerProperty);
textField.setTextFormatter(formatter);
Jeśli nie chcesz, nie potrzebujesz filtra wielokrotnego użytku, możesz zamiast tego zrobić ten fantazyjny jednolinijkowy:
TextFormatter<Integer> formatter = new TextFormatter<>(
new IntegerStringConverter(),
defaultValue,
c -> Pattern.matches("\\d*", c.getText()) ? c : null );
czasami masz wyjątek, ponieważ liczba może być zbyt duża.
schlagi123
1
Wskazówka: zamień wyrażenie regularne „\\ d +” na „\\ d *”. Umożliwi to usunięcie wszystkich znaków z pola wprowadzania tekstu (użyj klawisza Backspace / Delete, aby wyczyścić pole).
Guus,
1
Nie zapomnij ustawić pozycji karetki po przywróceniu jej starej wartości:textField.positionCaret(textField.getLength());
hsson
Zmień pierwszy warunek if na: if (newValue.matches("\\d*") && newValue.getText().length < 5) jeśli chcesz w tym przypadku ograniczyć dane wejściowe do 4 cyfr.
Cappuccino90
@ Cappuccino90 Powinieneś zmienić instrukcje, ponieważ sprawdzanie długości jest znacznie tańsze przy każdym trafieniu niż analizowanie wyrażenia regularnego
znaczy,
9
Począwszy od Java SE 8u40 , w takiej sytuacji można użyć „ liczby całkowitej ”, która Spinnerpozwala bezpiecznie wybrać prawidłową liczbę całkowitą za pomocą klawiszy strzałek w górę / w dół lub strzałek w górę / w dół na klawiaturze.
Można również zdefiniować wartość minimalną , maksymalną i początkową, aby ograniczyć dozwolone wartości i kwotę, o którą można zwiększać lub zmniejszać, na krok.
Na przykład
// Creates an integer spinner with 1 as min, 10 as max and 2 as initial value
Spinner<Integer> spinner1 = new Spinner<>(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 step
Spinner<Integer> spinner2 = new Spinner<>(0, 100, 10, 10);
Przykład wyniku z pokrętłem „ integer ” i „ podwójnym ” pokrętłem
Spinner jest tekst kontrola pole single-linia, która pozwala użytkownikowi wybrać liczbę lub wartość obiektu z uporządkowanej sekwencji takich wartości. Pokrętła zazwyczaj zapewniają parę małych przycisków ze strzałkami do przechodzenia między elementami sekwencji. Klawisze strzałek w górę / w dół na klawiaturze również przełączają elementy. Użytkownik może również mieć możliwość wpisania (dozwolonej) wartości bezpośrednio do pokrętła. Chociaż pola kombi zapewniają podobną funkcjonalność, czasami preferowane są pokrętła, ponieważ nie wymagają rozwijanej listy, która może zasłaniać ważne dane, a także dlatego, że pozwalają na takie funkcje, jak zawijanie od wartości maksymalnej do minimalnej (np. od największej dodatniej liczby całkowitej do 0).
ifKlauzula jest ważne, aby wejść rączki jak 0,5 D lub 0.7f, które są prawidłowo przetwarzane przez Int.parseInt (), ale nie powinien pojawić się w polu tekstowym.
Co? Od kiedy 0.5d jest poprawnie analizowane przez Integer.parseInt () ?! Wyrzuca wyjątek java.lang.NumberFormatException: Dla ciągu wejściowego: „0.5d” (zgodnie z oczekiwaniami, ponieważ nie jest to liczba całkowita)
Burkhard
4
Wypróbuj ten prosty kod, który wykona zadanie.
DecimalFormat format = new DecimalFormat( "#.0" );
TextField field = new TextField();
field.setTextFormatter( new TextFormatter<>(c ->
{
if ( c.getControlNewText().isEmpty() )
{
return c;
}
ParsePosition parsePosition = new ParsePosition( 0 );
Object object = format.parse( c.getControlNewText(), parsePosition );
if ( object == null || parsePosition.getIndex() < c.getControlNewText().length() )
{
returnnull;
}
else
{
return c;
}
}));
Ta metoda umożliwia TextField zakończenie całego przetwarzania (bezpieczne kopiowanie / wklejanie / cofanie). Nie wymaga rozszerzania klas i pozwala zdecydować, co zrobić z nowym tekstem po każdej zmianie (aby wypchnąć go do logiki, wrócić do poprzedniej wartości, a nawet zmodyfikować).
// 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());
}
);
W twoim przypadku po prostu dodaj tę logikę do środka. Działa świetnie.
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. Napotkałem ten problem kilka tygodni temu. Ponieważ interfejs API nie zapewnia kontroli, aby to osiągnąć,
możesz użyć własnego. Użyłem czegoś takiego:
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()}
}
Jest używany w taki sam sposób, jak normalny TextBox,
ale ma również valueatrybut, który przechowuje wprowadzoną liczbę całkowitą.
Gdy formant traci fokus, sprawdza poprawność wartości i przywraca ją (jeśli nie jest poprawna).
ten kod Stwórz swój textField Zaakceptuj tylko numer
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));
}
}
});
privatesynchronizedvoidnumericSanitization(ObservableValue<? extends String> observable, String oldValue, String newValue){
final String allowedPattern = "\\d*";
if (!newValue.matches(allowedPattern)) {
this.dataText.setText(oldValue);
}
}
Zsynchronizowano słowo kluczoweDodano aby zapobiec możliwemu problemowi z blokadą renderowania w javafx, jeśli setText zostanie wywołany przed zakończeniem wykonywania starego. Jest to łatwe do odtworzenia, jeśli naprawdę szybko zaczniesz wpisywać złe znaki.
Kolejną zaletą jest to, że zachowujesz tylko jeden wzór do dopasowania i po prostu cofasz. Jest to lepsze, ponieważ można łatwo odrzucić rozwiązanie dla różnych wzorców sanityzacji.
Odpowiedzi:
Bardzo stary wątek, ale wydaje się schludniejszy i po wklejeniu usuwa znaki nienumeryczne.
// force the field to be numeric only textField.textProperty().addListener(new ChangeListener<String>() { @Override public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) { if (!newValue.matches("\\d*")) { textField.setText(newValue.replaceAll("[^\\d]", "")); } } });
źródło
\\D+
(lub po prostu\\D
) zamiast[^\\d]
, jeśli chcesz zaoszczędzić kilka znaków.Integer.parseInt(newValue)
i użyćtry
icatch
wykryć błąd naNumberFormatException
Aktualizacja kwiecień 2016 r
Ta odpowiedź powstała kilka lat temu, a pierwotna odpowiedź jest obecnie w dużej mierze przestarzała.
Od wersji Java 8u40 Java ma TextFormatter, który zwykle najlepiej nadaje się do wymuszania wprowadzania określonych formatów, takich jak liczby, w polach tekstowych JavaFX:
Zobacz także inne odpowiedzi na to pytanie, które wyraźnie wspominają o TextFormatter.
Oryginalna odpowiedź
W tym tekście jest kilka przykładów , powieliłem jeden z poniższych przykładów:
// 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. class IntField extends TextField { final private IntegerProperty value; final private int minValue; final private int maxValue; // expose an integer value property for the text field. public int getValue() { return value.getValue(); } public void setValue(int newValue) { value.setValue(newValue); } public IntegerProperty valueProperty() { return value; } IntField(int minValue, int maxValue, int initialValue) { if (minValue > maxValue) throw new IllegalArgumentException( "IntField min value " + minValue + " greater than max value " + maxValue ); if (maxValue < minValue) throw new IllegalArgumentException( "IntField max value " + minValue + " less than min value " + maxValue ); if (!((minValue <= initialValue) && (initialValue <= maxValue))) throw new IllegalArgumentException( "IntField initialValue " + initialValue + " not between " + minValue + " and " + maxValue ); // initialize the field values. this.minValue = minValue; this.maxValue = maxValue; value = new SimpleIntegerProperty(initialValue); setText(initialValue + ""); final IntField 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(new ChangeListener<Number>() { @Override public void changed(ObservableValue<? extends Number> 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, new EventHandler<KeyEvent>() { @Override public void 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(new ChangeListener<String>() { @Override public void changed(ObservableValue<? extends String> observableValue, String oldValue, String newValue) { if (newValue == null || "".equals(newValue) || (intField.minValue<0 && "-".equals(newValue))) { value.setValue(0); return; } final int intValue = Integer.parseInt(newValue); if (intField.minValue > intValue || intValue > intField.maxValue) { textProperty().setValue(oldValue); } value.set(Integer.parseInt(textProperty().get())); } }); } }
źródło
Wiem, że to dość stary wątek, ale dla przyszłych czytelników jest tutaj inne rozwiązanie, które uznałem za dość intuicyjne:
public class NumberTextField extends TextField { @Override public void replaceText(int start, int end, String text) { if (validate(text)) { super.replaceText(start, end, text); } } @Override public void replaceSelection(String text) { if (validate(text)) { super.replaceSelection(text); } } private boolean validate(String text) { return text.matches("[0-9]*"); } }
Edycja: dziękuję none_ i SCBoy za sugerowane ulepszenia.
źródło
text.matches("\\d+");
i nie mogę usunąć żadnych znaków z pola tekstowegoPocząwszy od JavaFX 8u40, można ustawić obiekt TextFormatter w polu tekstowym:
UnaryOperator<Change> filter = change -> { String text = change.getText(); if (text.matches("[0-9]*")) { return change; } return null; }; TextFormatter<String> textFormatter = new TextFormatter<>(filter); fieldNport = new TextField(); fieldNport.setTextFormatter(textFormatter);
Pozwala to uniknąć podklas i zduplikowanych zdarzeń zmiany, które otrzymasz, gdy dodasz odbiornik zmian do właściwości text i zmodyfikujesz tekst w tym detektorze.
źródło
TextInput
MaTextFormatter
które mogą być wykorzystane do formatu, konwersji i ograniczyć rodzaje tekstów, które mogą być wprowadzane.TextFormatter
Posiada filtr, który może być stosowany do odrzucenia wejście. Musimy ustawić tę opcję, aby odrzucić wszystko, co nie jest prawidłową liczbą całkowitą. Posiada również konwerter, który musimy ustawić, aby przekonwertować wartość ciągu na wartość całkowitą, którą możemy później powiązać.Utwórzmy filtr wielokrotnego użytku:
public class IntegerFilter implements UnaryOperator<TextFormatter.Change> { private final static Pattern DIGIT_PATTERN = Pattern.compile("\\d*"); @Override public Change apply(TextFormatter.Change aT) { return DIGIT_PATTERN.matcher(aT.getText()).matches() ? aT : null; } }
Filtr może zrobić jedną z trzech rzeczy, może zwrócić niezmodyfikowaną zmianę, aby zaakceptować ją taką, jaka jest, może zmienić zmianę w sposób, który uzna za stosowny, lub może powrócić,
null
aby odrzucić zmianę w całości.Użyjemy standardu
IntegerStringConverter
jako konwertera.Łącząc to wszystko mamy:
TextField textField = ...; TextFormatter<Integer> formatter = new TextFormatter<>( new IntegerStringConverter(), // Standard converter form JavaFX defaultValue, new IntegerFilter()); formatter.valueProperty().bindBidirectional(myIntegerProperty); textField.setTextFormatter(formatter);
Jeśli nie chcesz, nie potrzebujesz filtra wielokrotnego użytku, możesz zamiast tego zrobić ten fantazyjny jednolinijkowy:
TextFormatter<Integer> formatter = new TextFormatter<>( new IntegerStringConverter(), defaultValue, c -> Pattern.matches("\\d*", c.getText()) ? c : null );
źródło
Nie lubię wyjątków, dlatego użyłem
matches
funkcji z String-Classtext.textProperty().addListener(new ChangeListener<String>() { @Override public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) { if (newValue.matches("\\d*")) { int value = Integer.parseInt(newValue); } else { text.setText(oldValue); } } });
źródło
textField.positionCaret(textField.getLength());
if (newValue.matches("\\d*") && newValue.getText().length < 5)
jeśli chcesz w tym przypadku ograniczyć dane wejściowe do 4 cyfr.Począwszy od Java SE 8u40 , w takiej sytuacji można użyć „ liczby całkowitej ”, która
Spinner
pozwala bezpiecznie wybrać prawidłową liczbę całkowitą za pomocą klawiszy strzałek w górę / w dół lub strzałek w górę / w dół na klawiaturze.Można również zdefiniować wartość minimalną , maksymalną i początkową, aby ograniczyć dozwolone wartości i kwotę, o którą można zwiększać lub zmniejszać, na krok.
Na przykład
// Creates an integer spinner with 1 as min, 10 as max and 2 as initial value Spinner<Integer> spinner1 = new Spinner<>(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 step Spinner<Integer> spinner2 = new Spinner<>(0, 100, 10, 10);
Przykład wyniku z pokrętłem „ integer ” i „ podwójnym ” pokrętłem
Więcej szczegółów na temat formantu Spinner
źródło
Preferowana odpowiedź może być jeszcze mniejsza, jeśli używasz Java 1.8 Lambdas
textfield.textProperty().addListener((observable, oldValue, newValue) -> { if (newValue.matches("\\d*")) return; textfield.setText(newValue.replaceAll("[^\\d]", "")); });
źródło
TextField text = new TextField(); text.textProperty().addListener(new ChangeListener<String>() { @Override public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) { try { Integer.parseInt(newValue); if (newValue.endsWith("f") || newValue.endsWith("d")) { manualPriceInput.setText(newValue.substring(0, newValue.length()-1)); } } catch (ParseException e) { text.setText(oldValue); } } });
if
Klauzula jest ważne, aby wejść rączki jak 0,5 D lub 0.7f, które są prawidłowo przetwarzane przez Int.parseInt (), ale nie powinien pojawić się w polu tekstowym.źródło
Wypróbuj ten prosty kod, który wykona zadanie.
DecimalFormat format = new DecimalFormat( "#.0" ); TextField field = new TextField(); field.setTextFormatter( new TextFormatter<>(c -> { if ( c.getControlNewText().isEmpty() ) { return c; } ParsePosition parsePosition = new ParsePosition( 0 ); Object object = format.parse( c.getControlNewText(), parsePosition ); if ( object == null || parsePosition.getIndex() < c.getControlNewText().length() ) { return null; } else { return c; } }));
źródło
Jeśli chcesz zastosować ten sam detektor do więcej niż jednego pola TextField, oto najprostsze rozwiązanie:
TextField txtMinPrice, txtMaxPrice = new TextField(); ChangeListener<String> forceNumberListener = (observable, oldValue, newValue) -> { if (!newValue.matches("\\d*")) ((StringProperty) observable).set(oldValue); }; txtMinPrice.textProperty().addListener(forceNumberListener); txtMaxPrice.textProperty().addListener(forceNumberListener);
źródło
Ten pracował dla mnie.
public void RestrictNumbersOnly(TextField tf){ tf.textProperty().addListener(new ChangeListener<String>() { @Override public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) { if (!newValue.matches("|[-\\+]?|[-\\+]?\\d+\\.?|[-\\+]?\\d+\\.?\\d+")){ tf.setText(oldValue); } } }); }
źródło
Chcę pomóc w moim pomyśle, łącząc odpowiedź Evan Knowles z
TextFormatter
z JavaFX 8textField.setTextFormatter(new TextFormatter<>(c -> { if (!c.getControlNewText().matches("\\d*")) return null; else return c; } ));
więc powodzenia;) zachowaj spokój i koduj java
źródło
Oto prosta klasa, która obsługuje podstawowe walidacje
TextField
, używającTextFormatter
wprowadzonych w JavaFX 8u40EDYTOWAĆ:
(Kod dodany do komentarza Floern)
import java.text.DecimalFormatSymbols; import java.util.regex.Pattern; import javafx.beans.NamedArg; import javafx.scene.control.TextFormatter; import javafx.scene.control.TextFormatter.Change; public class TextFieldValidator { private static final String CURRENCY_SYMBOL = DecimalFormatSymbols.getInstance().getCurrencySymbol(); private static final char DECIMAL_SEPARATOR = DecimalFormatSymbols.getInstance().getDecimalSeparator(); private final Pattern INPUT_PATTERN; public TextFieldValidator(@NamedArg("modus") ValidationModus modus, @NamedArg("countOf") int countOf) { this(modus.createPattern(countOf)); } public TextFieldValidator(@NamedArg("regex") String regex) { this(Pattern.compile(regex)); } public TextFieldValidator(Pattern inputPattern) { INPUT_PATTERN = inputPattern; } public static TextFieldValidator maxFractionDigits(int countOf) { return new TextFieldValidator(maxFractionPattern(countOf)); } public static TextFieldValidator maxIntegers(int countOf) { return new TextFieldValidator(maxIntegerPattern(countOf)); } public static TextFieldValidator integersOnly() { return new TextFieldValidator(integersOnlyPattern()); } public TextFormatter<Object> getFormatter() { return new TextFormatter<>(this::validateChange); } private Change validateChange(Change c) { if (validate(c.getControlNewText())) { return c; } return null; } public boolean validate(String input) { return INPUT_PATTERN.matcher(input).matches(); } private static Pattern maxFractionPattern(int countOf) { return Pattern.compile("\\d*(\\" + DECIMAL_SEPARATOR + "\\d{0," + countOf + "})?"); } private static Pattern maxCurrencyFractionPattern(int countOf) { return Pattern.compile("^\\" + CURRENCY_SYMBOL + "?\\s?\\d*(\\" + DECIMAL_SEPARATOR + "\\d{0," + countOf + "})?\\s?\\" + CURRENCY_SYMBOL + "?"); } private static Pattern maxIntegerPattern(int countOf) { return Pattern.compile("\\d{0," + countOf + "}"); } private static Pattern integersOnlyPattern() { return Pattern.compile("\\d*"); } public enum ValidationModus { MAX_CURRENCY_FRACTION_DIGITS { @Override public Pattern createPattern(int countOf) { return maxCurrencyFractionPattern(countOf); } }, MAX_FRACTION_DIGITS { @Override public Pattern createPattern(int countOf) { return maxFractionPattern(countOf); } }, MAX_INTEGERS { @Override public Pattern createPattern(int countOf) { return maxIntegerPattern(countOf); } }, INTEGERS_ONLY { @Override public Pattern createPattern(int countOf) { return integersOnlyPattern(); } }; public abstract Pattern createPattern(int countOf); } }
Możesz go używać w ten sposób:
textField.setTextFormatter(new TextFieldValidator(ValidationModus.INTEGERS_ONLY).getFormatter());
lub możesz utworzyć instancję w pliku fxml i zastosować ją do customTextField z odpowiednimi właściwościami.
app.fxml:
<fx:define> <TextFieldValidator fx:id="validator" modus="INTEGERS_ONLY"/> </fx:define>
CustomTextField.class:
public class CustomTextField { private TextField textField; public CustomTextField(@NamedArg("validator") TextFieldValidator validator) { this(); textField.setTextFormatter(validator.getFormatter()); } }
Kod na githubie
źródło
Oto czego używam:
private TextField textField; textField.textProperty().addListener(new ChangeListener<String>() { @Override public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) { if(!newValue.matches("[0-9]*")){ textField.setText(oldValue); } } });
To samo w notacji lambda wyglądałoby tak:
private TextField textField; textField.textProperty().addListener((observable, oldValue, newValue) -> { if(!newValue.matches("[0-9]*")){ textField.setText(oldValue); } });
źródło
Ta metoda umożliwia TextField zakończenie całego przetwarzania (bezpieczne kopiowanie / wklejanie / cofanie). Nie wymaga rozszerzania klas i pozwala zdecydować, co zrobić z nowym tekstem po każdej zmianie (aby wypchnąć go do logiki, wrócić do poprzedniej wartości, a nawet zmodyfikować).
// 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()); } );
W twoim przypadku po prostu dodaj tę logikę do środka. Działa świetnie.
if (newValue.equals("")) return; try { Integer i = Integer.valueOf(newValue); // do what you want with this i } catch (Exception e) { ((StringProperty)observable).setValue(oldValue); }
źródło
Mmmm. Napotkałem ten problem kilka tygodni temu. Ponieważ interfejs API nie zapewnia kontroli, aby to osiągnąć,
możesz użyć własnego. Użyłem czegoś takiego:
public class IntegerBox extends TextBox { 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()} }
Jest używany w taki sam sposób, jak normalny
TextBox
,ale ma również
value
atrybut, który przechowuje wprowadzoną liczbę całkowitą.Gdy formant traci fokus, sprawdza poprawność wartości i przywraca ją (jeśli nie jest poprawna).
źródło
ten kod Stwórz swój textField Zaakceptuj tylko numer
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)); } } });
źródło
Ten kod działa dobrze, nawet jeśli spróbujesz skopiować / wkleić.
myTextField.textProperty().addListener((observable, oldValue, newValue) -> { if (!newValue.matches("\\d*")) { myTextField.setText(oldValue); } });
źródło
W ostatnich aktualizacjach JavaFX musisz ustawić nowy tekst w metodzie Platform.runLater, tak jak poniżej:
private void set_normal_number(TextField textField, String oldValue, String newValue) { try { int p = textField.getCaretPosition(); if (!newValue.matches("\\d*")) { Platform.runLater(() -> { textField.setText(newValue.replaceAll("[^\\d]", "")); textField.positionCaret(p); }); } } catch (Exception e) { } }
Dobrym pomysłem jest również ustawienie pozycji karetki.
źródło
Platform.runLater
jest potrzebny?Chciałbym poprawić odpowiedź Evana Knowlesa: https://stackoverflow.com/a/30796829/2628125
W moim przypadku miałem klasę z handlerami dla części UI Component. Inicjalizacja:
this.dataText.textProperty().addListener((observable, oldValue, newValue) -> this.numericSanitization(observable, oldValue, newValue));
Oraz metoda numbericSanitization:
private synchronized void numericSanitization(ObservableValue<? extends String> observable, String oldValue, String newValue) { final String allowedPattern = "\\d*"; if (!newValue.matches(allowedPattern)) { this.dataText.setText(oldValue); } }
Zsynchronizowano słowo kluczoweDodano aby zapobiec możliwemu problemowi z blokadą renderowania w javafx, jeśli setText zostanie wywołany przed zakończeniem wykonywania starego. Jest to łatwe do odtworzenia, jeśli naprawdę szybko zaczniesz wpisywać złe znaki.
Kolejną zaletą jest to, że zachowujesz tylko jeden wzór do dopasowania i po prostu cofasz. Jest to lepsze, ponieważ można łatwo odrzucić rozwiązanie dla różnych wzorców sanityzacji.
źródło
rate_text.textProperty().addListener(new ChangeListener<String>() { @Override public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) { String s=""; for(char c : newValue.toCharArray()){ if(((int)c >= 48 && (int)c <= 57 || (int)c == 46)){ s+=c; } } rate_text.setText(s); } });
Działa to dobrze, ponieważ pozwala wprowadzić tylko wartość całkowitą i wartość dziesiętną (z kodem ASCII 46).
źródło