Tópico muito antigo, mas parece mais organizado e remove os caracteres não numéricos se colado.
// 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]", ""));
}
}
});
Funciona maravilhosamente. Observe que você também pode usar \\D+(ou apenas \\D) em vez de [^\\d], se quiser salvar alguns caracteres.
ricky3350
5
Ainda mais simples é definir o texto de volta para oldValue. Dessa forma, você não precisa mexer em substituições de regex (o que não funcionou para mim, infelizmente).
geisterfurz007
@ geisterfurz007 Isso dá a opção de remover não-numéricos do texto colado.
Evan Knowles
10
Desatualizado, consulte a resposta do TextFormatter abaixo.
gerardw
3
Também poderia simplesmente usar Integer.parseInt(newValue)e usar trye catchlocalizar um erroNumberFormatException
Pixel
44
Atualização de abril de 2016
Essa resposta foi criada há alguns anos e a resposta original está obsoleta agora.
Desde Java 8u40, Java tem um TextFormatter que geralmente é melhor para forçar a entrada de formatos específicos, como numéricos, em TextFields JavaFX:
Veja também outras respostas a esta pergunta que mencionam especificamente TextFormatter.
Resposta Original
Existem alguns exemplos disso nesta essência , eu dupliquei um dos exemplos abaixo:
// 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()));
}
});
}
}
Alguém sabe qual regex usar para números decimais (por exemplo, 123.456)? O valor do parâmetro de função validate (text) "text" é o último caractere editado pelo usuário, não a string inteira no campo de texto, portanto, a regex pode não corresponder corretamente. Por exemplo, estou usando este comando da seguinte maneira: text.matches("\\d+"); e não consigo excluir nenhum caractere no campo de texto
Acho que é uma boa solução, mas gostaria de mudar uma coisa. Em vez de escrever text.matches ("[0-9] *"), eu criaria uma variável para o padrão e compilaria. Em seu código, o padrão é compilado toda vez que alguém escreve um caractere em um campo, e isso é caro para CPU e memória. Então, eu adicionaria a variável: private static Pattern integerPattern = Pattern.compile ("[0-9] *"); E substitua validate body por: integerPattern.matcher (text) .matches ();
P. Jowko
38
A partir do JavaFX 8u40, você pode definir um objeto TextFormatter em um campo de texto:
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);
Isso evita a criação de subclasses e eventos de alteração duplicados que você obterá ao adicionar um ouvinte de alteração à propriedade de texto e modificar o texto nesse ouvinte.
O TextInputtem um TextFormatterque pode ser usado para formatar, converter e limitar os tipos de texto que podem ser inseridos.
O TextFormatterpossui um filtro que pode ser usado para rejeitar entradas. Precisamos definir isso para rejeitar qualquer coisa que não seja um número inteiro válido. Ele também tem um conversor que precisamos definir para converter o valor da string em um valor inteiro que podemos ligar mais tarde.
O filtro pode fazer uma das três coisas: pode retornar a alteração sem modificações para aceitá-la como está, pode alterar a alteração de alguma forma que considere adequada ou pode retornar nullpara rejeitar a alteração totalmente.
TextField textField = ...;
TextFormatter<Integer> formatter = new TextFormatter<>(
new IntegerStringConverter(), // Standard converter form JavaFX
defaultValue,
new IntegerFilter());
formatter.valueProperty().bindBidirectional(myIntegerProperty);
textField.setTextFormatter(formatter);
Se você quiser não precisa de um filtro reutilizável, pode fazer esta linha sofisticada:
TextFormatter<Integer> formatter = new TextFormatter<>(
new IntegerStringConverter(),
defaultValue,
c -> Pattern.matches("\\d*", c.getText()) ? c : null );
às vezes você tem uma exceção, porque o nuber pode ser muito grande.
schlagi123
1
Dica: substitua o regex "\\ d +" por "\\ d *". Isso permitirá que você remova todos os caracteres do campo de entrada de texto (use backspace / delete para limpar o campo).
Guus
1
Não se esqueça de definir a posição circunflexo depois de defini-lo de volta para o valor antigo:textField.positionCaret(textField.getLength());
hsson
Altere a primeira condição se para: if (newValue.matches("\\d*") && newValue.getText().length < 5) se quiser limitar a entrada a 4 dígitos neste caso.
Cappuccino90
@ Cappuccino90 Você deve mudar as instruções porque a verificação de comprimento é muito mais barata em cada
ocorrência do
9
A partir do Java SE 8u40 , para tal necessidade você pode usar um " inteiro " Spinnerpermitindo selecionar com segurança um inteiro válido usando as teclas de seta para cima / seta para baixo do teclado ou os botões de seta para cima / seta para baixo fornecidos.
Você também pode definir um mínimo , um máximo e um valor inicial para limitar os valores permitidos e uma quantidade para aumentar ou diminuir, por etapa.
Por exemplo
// 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);
Exemplo de resultado com um spinner " inteiro " e um spinner " duplo "
Um controle giratório é um controle de campo de texto de linha única que permite ao usuário selecionar um número ou valor de objeto em uma sequência ordenada de tais valores. Spinners geralmente fornecem um par de pequenos botões de seta para percorrer os elementos da sequência. As teclas de seta para cima / seta para baixo do teclado também percorrem os elementos. O usuário também pode digitar um valor (legal) diretamente no botão giratório. Embora as caixas de combinação forneçam funcionalidade semelhante, os spinners às vezes são preferidos porque não requerem uma lista suspensa que pode obscurecer dados importantes e também porque permitem recursos como quebra automática do valor máximo de volta ao valor mínimo (por exemplo, do maior número inteiro positivo a 0).
A ifcláusula é importante para lidar com entradas como 0,5d ou 0,7f, que são analisadas corretamente por Int.parseInt (), mas não devem aparecer no campo de texto.
Woot? Desde quando 0.5d é analisado corretamente por Integer.parseInt () ?! Ele lança um java.lang.NumberFormatException: Para string de entrada: "0.5d" (como esperado, já que não é um inteiro)
Burkhard
4
Tente este código simples, ele fará o trabalho.
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;
}
}));
Este método permite que TextField termine todo o processamento (copiar / colar / desfazer seguro). Não requer estender classes e permite que você decida o que fazer com o novo texto após cada mudança (para colocá-lo na lógica, ou voltar ao valor anterior, ou mesmo modificá-lo).
// 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());
}
);
Para o seu caso, basta adicionar essa lógica dentro. Funciona perfeitamente.
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. Eu tive esse problema semanas atrás. Como a API não fornece um controle para isso,
você pode usar o seu próprio. Eu usei algo como:
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()}
}
É usado da mesma forma que um normal TextBox,
mas também tem um valueatributo que armazena o inteiro inserido.
Quando o controle perde o foco, ele valida o valor e o reverte (se não for válido).
este código Faça seu textField Aceitar apenas o número
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);
}
}
Palavra-chave - sincronizada palavra- é adicionada para evitar um possível problema de bloqueio de renderização em javafx se setText for chamado antes que o antigo termine a execução. É fácil de reproduzir se você começar a digitar os caracteres errados muito rápido.
Outra vantagem é que você mantém apenas um padrão para corresponder e apenas faz o rollback. É melhor porque você pode abstrair facilmente a solução para diferentes padrões de sanitização.
Respostas:
Tópico muito antigo, mas parece mais organizado e remove os caracteres não numéricos se colado.
// 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]", "")); } } });
fonte
\\D+
(ou apenas\\D
) em vez de[^\\d]
, se quiser salvar alguns caracteres.Integer.parseInt(newValue)
e usartry
ecatch
localizar um erroNumberFormatException
Atualização de abril de 2016
Essa resposta foi criada há alguns anos e a resposta original está obsoleta agora.
Desde Java 8u40, Java tem um TextFormatter que geralmente é melhor para forçar a entrada de formatos específicos, como numéricos, em TextFields JavaFX:
Veja também outras respostas a esta pergunta que mencionam especificamente TextFormatter.
Resposta Original
Existem alguns exemplos disso nesta essência , eu dupliquei um dos exemplos abaixo:
// 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())); } }); } }
fonte
Eu sei que este é um tópico bastante antigo, mas para futuros leitores, aqui está outra solução que achei bastante intuitiva:
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]*"); } }
Edit: Obrigado none_ e SCBoy por suas sugestões de melhorias.
fonte
text.matches("\\d+");
e não consigo excluir nenhum caractere no campo de textoA partir do JavaFX 8u40, você pode definir um objeto TextFormatter em um campo de texto:
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);
Isso evita a criação de subclasses e eventos de alteração duplicados que você obterá ao adicionar um ouvinte de alteração à propriedade de texto e modificar o texto nesse ouvinte.
fonte
O
TextInput
tem umTextFormatter
que pode ser usado para formatar, converter e limitar os tipos de texto que podem ser inseridos.O
TextFormatter
possui um filtro que pode ser usado para rejeitar entradas. Precisamos definir isso para rejeitar qualquer coisa que não seja um número inteiro válido. Ele também tem um conversor que precisamos definir para converter o valor da string em um valor inteiro que podemos ligar mais tarde.Vamos criar um filtro reutilizável:
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; } }
O filtro pode fazer uma das três coisas: pode retornar a alteração sem modificações para aceitá-la como está, pode alterar a alteração de alguma forma que considere adequada ou pode retornar
null
para rejeitar a alteração totalmente.Usaremos o padrão
IntegerStringConverter
como conversor.Juntando tudo, temos:
TextField textField = ...; TextFormatter<Integer> formatter = new TextFormatter<>( new IntegerStringConverter(), // Standard converter form JavaFX defaultValue, new IntegerFilter()); formatter.valueProperty().bindBidirectional(myIntegerProperty); textField.setTextFormatter(formatter);
Se você quiser não precisa de um filtro reutilizável, pode fazer esta linha sofisticada:
TextFormatter<Integer> formatter = new TextFormatter<>( new IntegerStringConverter(), defaultValue, c -> Pattern.matches("\\d*", c.getText()) ? c : null );
fonte
Não gosto de exceções, por isso usei a
matches
função 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); } } });
fonte
textField.positionCaret(textField.getLength());
if (newValue.matches("\\d*") && newValue.getText().length < 5)
se quiser limitar a entrada a 4 dígitos neste caso.A partir do Java SE 8u40 , para tal necessidade você pode usar um " inteiro "
Spinner
permitindo selecionar com segurança um inteiro válido usando as teclas de seta para cima / seta para baixo do teclado ou os botões de seta para cima / seta para baixo fornecidos.Você também pode definir um mínimo , um máximo e um valor inicial para limitar os valores permitidos e uma quantidade para aumentar ou diminuir, por etapa.
Por exemplo
// 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);
Exemplo de resultado com um spinner " inteiro " e um spinner " duplo "
Mais detalhes sobre o controle Spinner
fonte
A resposta preferida pode ser ainda menor se você usar Java 1.8 Lambdas
textfield.textProperty().addListener((observable, oldValue, newValue) -> { if (newValue.matches("\\d*")) return; textfield.setText(newValue.replaceAll("[^\\d]", "")); });
fonte
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); } } });
A
if
cláusula é importante para lidar com entradas como 0,5d ou 0,7f, que são analisadas corretamente por Int.parseInt (), mas não devem aparecer no campo de texto.fonte
Tente este código simples, ele fará o trabalho.
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; } }));
fonte
Se você deseja aplicar o mesmo ouvinte a mais de um TextField, aqui está a solução mais simples:
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);
fonte
Este funcionou para mim.
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); } } }); }
fonte
Quero ajudar com minha ideia combinando a resposta de Evan Knowles com o
TextFormatter
JavaFX 8textField.setTextFormatter(new TextFormatter<>(c -> { if (!c.getControlNewText().matches("\\d*")) return null; else return c; } ));
então boa sorte;) mantenha a calma e codifique java
fonte
Aqui está uma classe simples que lida com algumas validações básicas em
TextField
, usandoTextFormatter
introduzido no JavaFX 8u40EDITAR:
(Código adicionado em relação ao comentário de 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); } }
Você pode usá-lo assim:
textField.setTextFormatter(new TextFieldValidator(ValidationModus.INTEGERS_ONLY).getFormatter());
ou você pode instanciá-lo em um arquivo fxml e aplicá-lo a um customTextField com as propriedades correspondentes.
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()); } }
Código no github
fonte
Isso é o que eu uso:
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); } } });
O mesmo na notação lambda seria:
private TextField textField; textField.textProperty().addListener((observable, oldValue, newValue) -> { if(!newValue.matches("[0-9]*")){ textField.setText(oldValue); } });
fonte
Este método permite que TextField termine todo o processamento (copiar / colar / desfazer seguro). Não requer estender classes e permite que você decida o que fazer com o novo texto após cada mudança (para colocá-lo na lógica, ou voltar ao valor anterior, ou mesmo modificá-lo).
// 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()); } );
Para o seu caso, basta adicionar essa lógica dentro. Funciona perfeitamente.
if (newValue.equals("")) return; try { Integer i = Integer.valueOf(newValue); // do what you want with this i } catch (Exception e) { ((StringProperty)observable).setValue(oldValue); }
fonte
Mmmm. Eu tive esse problema semanas atrás. Como a API não fornece um controle para isso,
você pode usar o seu próprio. Eu usei algo como:
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()} }
É usado da mesma forma que um normal
TextBox
,mas também tem um
value
atributo que armazena o inteiro inserido.Quando o controle perde o foco, ele valida o valor e o reverte (se não for válido).
fonte
este código Faça seu textField Aceitar apenas o número
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)); } } });
fonte
Este código funciona bem para mim, mesmo se você tentar copiar / colar.
myTextField.textProperty().addListener((observable, oldValue, newValue) -> { if (!newValue.matches("\\d*")) { myTextField.setText(oldValue); } });
fonte
Em atualizações recentes do JavaFX, você deve definir um novo texto no método Platform.runLater assim:
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) { } }
É uma boa ideia definir a posição do cursor também.
fonte
Platform.runLater
é necessário?Eu gostaria de melhorar a resposta de Evan Knowles: https://stackoverflow.com/a/30796829/2628125
No meu caso, tive aula com manipuladores para a parte do componente de interface do usuário. Inicialização:
this.dataText.textProperty().addListener((observable, oldValue, newValue) -> this.numericSanitization(observable, oldValue, newValue));
E o método 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); } }
Palavra-chave - sincronizada palavra- é adicionada para evitar um possível problema de bloqueio de renderização em javafx se setText for chamado antes que o antigo termine a execução. É fácil de reproduzir se você começar a digitar os caracteres errados muito rápido.
Outra vantagem é que você mantém apenas um padrão para corresponder e apenas faz o rollback. É melhor porque você pode abstrair facilmente a solução para diferentes padrões de sanitização.
fonte
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); } });
Isso funciona bem, pois permite que você insira apenas o valor inteiro e o valor decimal (com código ASCII 46).
fonte