JavaFX 将 TextField 的 TextFormatter 中的 valueProperty 绑定到 SimpleDoubleProperty

JavaFX Bind valueProperty from TextField's TextFormatter to SimpleDoubleProperty

我有一个 TextField,它被赋予了一个 TextFormatter,它有一个过滤器,可以接受文本字段的输入,并确保它是双精度格式。然后它使用 DoubleStringConverter 将过滤后的文本转换为双精度值。这是在自定义 FXML 组件中。请参阅下面的最小示例。

public SomeComponent implements Initializable {
    @FXML
    public TextField inputField;

    public int min;

    public void initialize(URL location, ResourceBundle resources) {
        UnaryOperator<TextFormatter.Change> doubleFilter = change -> {
            String newText = change.getControlNewText();
            if (newText.matches("-?[0-9]{1,13}(\.[0-9]*)?")) { 
                return change;
            }
            return null;
        };

        inputField.setTextFormatter(new TextFormatter<>(new DoubleStringConverter(), min, doubleFilter)); 
    }
}

另一个使用该组件的 FXML 组件...

public SomeView implements Initializable {
    @FXML
    SomeComponent comp;
    public void initialize(URL location, ResourceBundle resources) {
        comp.inputField.getTextFormatter().valueProperty().bindBidirectional(SomeDataManagerClass.SomeSimpleDoubleProperty());
    }
}

bindBidirectional() 试图将 TextField 的转换值绑定到存在于其他地方的 SimpleDoubleProperty。但是这个returns出现如下错误:

method Property.bindBidirectional(Property<CAP#1>) is not applicable
(argument mismatch; SimpleDoubleProperty cannot be converted to Property<CAP#1>)

基本上我想利用 TextField 的值(不是 getText(),而是转换后的值)绑定到其他属性。

我意识到使用 TextFormatter 捕获的类型推断有问题,但我在 JavaDocs 中看不到显示如何使用 TextFormatter 的双精度值的任何地方。如果没有简单的方法从 TextField 中提取双精度值,那么使用 DoubleStringConverter 转换值有什么意义?我可以使用 Double.parseDouble(inputField.getText()),但如果我已经为该字段设置了一个不错的 TextFormatter,这似乎毫无意义。

如何在 SomeComponent 之外使用 TextFormatter 的 valueProperty?

textFormatter 属性 是一个 ObjectProperty<TextFormatter<?>>。由于 TextInputControl class 不是通用的,因此无法正确参数化 textFormatter 属性,因此使用通配符。这意味着每当您查询 属性 时,您都会得到一个 TextFormatter<?>,而不管之前是否将其设置为 TextFormatter<Double>。有几种方法可以解决这个问题:

  1. 将结果转换为您期望的任何泛型类型:

    var formatter = (TextFormatter<Number>) comp.inputField.getTextFormatter();
    formatter.valueProperty().bindBidirectional(SomeDataManagerClass.SomeSimpleDoubleProperty());
    

    当然,这会导致出现未经检查的演员表警告。如果需要,您可以通过 @SuppressWarnings("unchecked") 注释抑制警告,但操作仍然不安全。

  2. 保留您自己对 TextFormatter<Number> 的引用,并为其他代码提供获取它的方法。

    public SomeComponent implements Initializable {
    
        @FXML
        public TextField inputField;
    
        // maintain generic information
        private TextFormatter<Number> inputFieldFormatter;
    
        public int min;
    
        public void initialize(URL location, ResourceBundle resources) {
            UnaryOperator<TextFormatter.Change> doubleFilter = change -> {
                String newText = change.getControlNewText();
                if (newText.matches("-?[0-9]{1,13}(\.[0-9]*)?")) { 
                    return change;
                }
                return null;
            };
    
            inputFieldFormatter = new TextFormatter<>(new NumberStringConverter(), min, doubleFilter);
            inputField.setTextFormatter(inputFieldFormatter)); 
        }
    
        // use this method in your other controller
        public TextFormatter<Number> getInputFieldFormatter() {
            return inputFieldFormatter;
        }
    }
    

请注意,我在每种情况下都使用了 TextFormatter<Number>。这是因为 DoublePropertyProperty<Number> 并且 bindBidirectional 方法需要一个精确的泛型匹配,不像 bind 方法是上限。这也意味着必须使用 NumberStringConverter