JavaFX 8中带有TextFormatter和/或UnaryOperator的整数数字TextField [英] Numeric TextField for Integers in JavaFX 8 with TextFormatter and/or UnaryOperator

查看:544
本文介绍了JavaFX 8中带有TextFormatter和/或UnaryOperator的整数数字TextField的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用JavaFX 8的TextFormatter为整数创建一个数字TextField。

I am trying to create a numeric TextField for Integers by using the TextFormatter of JavaFX 8.

使用UnaryOperator的解决方案:

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

myNumericField.setTextFormatter(new TextFormatter<String>(integerFilter));

使用IntegerStringConverter的解决方案:

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

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

Both solutions have their own problems. With the UnaryOperator, I can only enter digits from 0 to 9 like intended, but I also need to enter negative values like "-512", where the sign is only allowed at the first position. Also I don't want numbers like "00016" which is still possible.

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

The IntegerStringConverter method works way better: Every invalid number like "-16-123" is not accepted and numbers like "0123" get converted to "123". But the conversion only happens when the text is commited (via pressing enter) or when the TextField loses its focus.

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

Is there a way to enforce the conversion of the second method with the IntegerStringConverter every time the value of the TextField is updated?

推荐答案

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

The converter is different to the filter: the converter specifies how to convert the text to a value, and the filter filters changes the user may make. It sounds like here you want both, but you want the filter to more accurately filter the changes that are allowed.

我通常觉得最容易检查新的值如果更改被接受,则发送文本。您希望选择 - ,然后是 1-9 ,后面有任意位数。允许空字符串很重要,否则用户将无法删除所有内容。

I usually find it easiest to check the new value of the text if the change were accepted. You want to optionally have a -, followed by 1-9 with any number of digits after it. It's important to allow an empty string, else the user won't be able to delete everything.

所以你可能需要像

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));

您甚至可以为过滤器添加更多功能,让它处理 - 以更智能的方式,例如

You can even add more functionality to the filter to let it process - in a smarter way, e.g.

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;
};

这将让用户按下 - at任何一点,它将切换整数的符号。

This will let the user press - at any point and it will toggle the sign of the integer.

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);
    }
}

这篇关于JavaFX 8中带有TextFormatter和/或UnaryOperator的整数数字TextField的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆