JavaFX 8中带有TextFormatter和/或UnaryOperator的整数的数字TextField

Sha*_*gle 10 java javafx numeric formatter textfield

我试图通过使用JavaFX 8的TextFormatter为整数创建一个数字TextField.

使用UnaryOperator解决方案:

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

myNumericField.setTextFormatter(new TextFormatter<String>(integerFilter));
Run Code Online (Sandbox Code Playgroud)

使用IntegerStringConverter的解决方案:

myNumericField.setTextFormatter(new TextFormatter<>(new IntegerStringConverter()));  
Run Code Online (Sandbox Code Playgroud)

两种解决方案都有自己的问题.使用UnaryOperator,我只能输入0到9之间的数字,但我还需要输入负值,如"-512",其中只允许在第一个位置使用符号.此外,我不希望像"00016"这样的数字仍然可能.

IntegerStringConverter方法效果更好:不接受每个无效的数字,如"-16-123",像"0123"这样的数字转换为"123".但转换仅在文本提交时(通过按Enter键)或TextField失去焦点时发生.

有没有办法在每次更新TextField的值时使用IntegerStringConverter强制转换第二个方法?

Jam*_*s_D 16

转换器与过滤器不同:转换器指定如何将文本转换为值,过滤器过滤用户可能进行的更改.这听起来像你想要的两个,但你希望过滤器更准确地过滤允许的更改.

如果接受更改,我通常会发现检查文本的新值最容易.您可以选择使用a -,后跟1-9任意数量的数字.允许空字符串很重要,否则用户将无法删除所有内容.

所以你可能需要类似的东西

UnaryOperator<Change> integerFilter = change -> {
    String newText = change.getControlNewText();
    if (newText.matches("-?([1-9][0-9]*)?")) { 
        return change;
    }
    return null;
};

myNumericField.setTextFormatter(
    new TextFormatter<Integer>(new IntegerStringConverter(), 0, integerFilter));
Run Code Online (Sandbox Code Playgroud)

您甚至可以向过滤器添加更多功能,以便-以更智能的方式进行处理,例如

UnaryOperator<Change> 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;
};
Run Code Online (Sandbox Code Playgroud)

这将让用户-在任何时候按下它,它将切换整数的符号.

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<Change> 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<Integer> converter = new IntegerStringConverter() {
            @Override
            public Integer fromString(String s) {
                if (s.isEmpty()) return 0 ;
                return super.fromString(s);
            }
        };

        TextFormatter<Integer> textFormatter = 
                new TextFormatter<Integer>(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);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 聪明地在数字组上使用`?`!正在考虑`-?([1-9]?| [1-9] [0-9] *)`,但这要干净得多! (2认同)
  • 我非常感谢您的努力,您的解决方案效果很好! (2认同)