Numérico TextField para enteros en JavaFX 8 con TextFormatter y / o UnaryOperator

Intento crear un TextField numérico para enteros utilizando TextFormatter de JavaFX 8.

Solución con UnaryOperator:

UnaryOperator integerFilter = change -> { String input = change.getText(); if (input.matches("[0-9]*")) { return change; } return null; }; myNumericField.setTextFormatter(new TextFormatter(integerFilter)); 

Solución con IntegerStringConverter:

 myNumericField.setTextFormatter(new TextFormatter(new IntegerStringConverter())); 

Ambas soluciones tienen sus propios problemas. Con UnaryOperator, solo puedo ingresar dígitos del 0 al 9 como se pretendía, pero también debo ingresar valores negativos como “-512”, donde el signo solo está permitido en la primera posición. Además, no quiero números como “00016”, que aún es posible.

El método IntegerStringConverter funciona mucho mejor: no se aceptan todos los números inválidos como “-16-123” y los números como “0123” se convierten a “123”. Pero la conversión solo ocurre cuando el texto está comprometido (al presionar enter) o cuando TextField pierde su foco.

¿Hay alguna manera de aplicar la conversión del segundo método con IntegerStringConverter cada vez que se actualiza el valor de TextField?

El convertidor es diferente del filtro: el convertidor especifica cómo convertir el texto a un valor y los filtros filtran los cambios que el usuario puede realizar. Parece que desea ambas cosas, pero desea que el filtro filtre con mayor precisión los cambios permitidos.

Por lo general, me resulta más fácil verificar el nuevo valor del texto si el cambio fue aceptado. Desea tener opcionalmente un - , seguido de 1-9 con cualquier número de dígitos después de él. Es importante permitir una cadena vacía, de lo contrario, el usuario no podrá eliminar todo.

Entonces probablemente necesites algo como

 UnaryOperator integerFilter = change -> { String newText = change.getControlNewText(); if (newText.matches("-?([1-9][0-9]*)?")) { return change; } return null; }; myNumericField.setTextFormatter( new TextFormatter(new IntegerStringConverter(), 0, integerFilter)); 

Incluso puede agregar más funcionalidades al filtro para permitir su procesamiento - de una manera más inteligente, por ejemplo

 UnaryOperator integerFilter = change -> { String newText = change.getControlNewText(); // if proposed change results in a valid value, return change as-is: if (newText.matches("-?([1-9][0-9]*)?")) { return change; } else if ("-".equals(change.getText()) ) { // if user types or pastes a "-" in middle of current text, // toggle sign of value: if (change.getControlText().startsWith("-")) { // if we currently start with a "-", remove first character: change.setText(""); change.setRange(0, 1); // since we're deleting a character instead of adding one, // the caret position needs to move back one, instead of // moving forward one, so we modify the proposed change to // move the caret two places earlier than the proposed change: change.setCaretPosition(change.getCaretPosition()-2); change.setAnchor(change.getAnchor()-2); } else { // otherwise just insert at the beginning of the text: change.setRange(0, 0); } return change ; } // invalid change, veto it by returning null: return null; }; 

Esto permitirá al usuario presionar - en cualquier punto y alternará el signo del número entero.

SSCCE:

 import java.util.function.UnaryOperator; import javafx.application.Application; import javafx.geometry.Pos; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.TextField; import javafx.scene.control.TextFormatter; import javafx.scene.control.TextFormatter.Change; import javafx.scene.layout.VBox; import javafx.stage.Stage; import javafx.util.StringConverter; import javafx.util.converter.IntegerStringConverter; public class IntegerFieldExample extends Application { @Override public void start(Stage primaryStage) { TextField integerField = new TextField(); UnaryOperator integerFilter = change -> { String newText = change.getControlNewText(); if (newText.matches("-?([1-9][0-9]*)?")) { return change; } else if ("-".equals(change.getText()) ) { if (change.getControlText().startsWith("-")) { change.setText(""); change.setRange(0, 1); change.setCaretPosition(change.getCaretPosition()-2); change.setAnchor(change.getAnchor()-2); return change ; } else { change.setRange(0, 0); return change ; } } return null; }; // modified version of standard converter that evaluates an empty string // as zero instead of null: StringConverter converter = new IntegerStringConverter() { @Override public Integer fromString(String s) { if (s.isEmpty()) return 0 ; return super.fromString(s); } }; TextFormatter textFormatter = new TextFormatter(converter, 0, integerFilter); integerField.setTextFormatter(textFormatter); // demo listener: textFormatter.valueProperty().addListener((obs, oldValue, newValue) -> System.out.println(newValue)); VBox root = new VBox(5, integerField, new Button("Click Me")); root.setAlignment(Pos.CENTER); Scene scene = new Scene(root, 300, 120); primaryStage.setScene(scene); primaryStage.show(); } public static void main(String[] args) { launch(args); } } 
  TextField txtpoint = new TextField(); txtpoint.textProperty().addListener(new ChangeListener() { @Override public void changed(ObservableValue observable, String oldValue, String newValue) { if (!newValue.isEmpty()) { try { long pointI = Integer.parseInt(newValue); txtpoint.setText(String.valueOf(pointI)); } catch (Exception e) { txtpoint.clear(); txtpoint.setText(getNumber(oldValue)); } } } }); private String getNumber(String value) { String n = ""; try { return String.valueOf(Integer.parseInt(value)); } catch (Exception e) { String[] array = value.split(""); for (String tab : array) { try { System.out.println(tab); n = n.concat(String.valueOf(Integer.parseInt(String.valueOf(tab)))); } catch (Exception ex) { System.out.println("not nomber"); } } return n; } } 
    Intereting Posts