JavaFX TextField: Alternative for Swing InputVerif

2020-04-19 09:39发布

问题:

I am looking for an alternative of Swing InputVerifier to JavaFX TextField.

The Swing InputVerifier will prevent input that does verify.

Consider the following Swing JTextField code:

InputVerifier iv = new InputVerifier() {
    /* (non-Javadoc)
     * @see javax.swing.InputVerifier#verify(javax.swing.JComponent)
     */
    @Override
    public boolean verify(JComponent input) {
        JTextField tf = (JTextField) input;
        if (!myRegExTool.matches(tf.getText())) {
            return false;
        }
        return true;
    }
};
jinstance.setInputVerifier(iv);

I could use TextField.setOnKeyTyped or a listener to TextField.textProperty to check the typed text. However that will not prevent invalid text to get into the TextField. I could however delete typed text that does not verify, but that is not a good solution.



Solution: As suggested by James_D a TextFormatter with a filter was the perfect solution

    UnaryOperator<Change> textFilter = change -> {
        String input = change.getText();
        if (!myRegExTool.matches(input)) {
            return null;
        }
        return change;
    };
    instance.setTextFormatter(new TextFormatter<String>(textFilter));

回答1:

I have IntegerField control with StringConverter, UnaryOperator and TextFormatter. Maybe helpful for you!

import javafx.scene.control.TextField;
import javafx.scene.control.TextFormatter;
import javafx.util.StringConverter;
import javafx.util.converter.IntegerStringConverter;
import java.util.function.UnaryOperator;

public class IntegerField extends TextField {

public IntegerField() {
    super();
    StringConverter<Integer> integerStringConverter = new IntegerStringConverter();
    UnaryOperator<TextFormatter.Change> filter = getFilter();
    setTextFormatter(new TextFormatter<>(integerStringConverter, null, filter));
    setOnAction(event -> integerStringConverter.fromString(this.getText()));
}

private UnaryOperator<TextFormatter.Change> getFilter() {
    return change -> {
        String text = change.getText();
        if (!change.isContentChange()) {
            return change;
        }
        if (text.matches("[0-9]*")) {
            return change;
        }
        return null;
    };
}

public Integer getValue() {
    return Integer.valueOf(this.getText());
}

}


回答2:

As first suggested by James_D a TextFormatter with filter was the solution.

TextField instance = new TextField();
UnaryOperator<Change> textFilter = change -> {
    String input = change.getText();
    if (!change.isContentChange()) {
        return change;
    }
    if (!myRegExTool.matches(input)) {
        return null;
    }
    return change;
};
instance.setTextFormatter(new TextFormatter<String>(textFilter));