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

3

我有一个TextField,它已经被赋予了TextFormatter,并且该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,但是会返回以下错误:
method Property.bindBidirectional(Property<CAP#1>) is not applicable
(argument mismatch; SimpleDoubleProperty cannot be converted to Property<CAP#1>)

本质上,我想利用TextField的值(而不是 getText() 获得的值)来绑定到其他属性。

我意识到TextFormatter的捕获类型推断存在问题,但我找不到JavaDocs中任何显示如何使用TextFormatter的double值的地方。如果没有一种简单的方法从TextField中提取该double值,那么使用DoubleStringConverter来转换值有什么意义呢?如果我已经费心设置了一个漂亮的TextFormatter,则使用 Double.parseDouble(inputField.getText()) 看起来就毫无意义了。

我如何在SomeComponent之外利用TextFormatter的valueProperty?

1个回答

3

textFormatter 属性是一个 ObjectProperty<TextFormatter<?>>。由于 TextInputControl 类不是泛型类,因此无法正确地参数化 textFormatter 属性,因此需要使用通配符。这意味着无论您之前将其设置为什么类型(例如,TextFormatter<Double>),每当查询该属性时,都将得到一个 TextFormatter<?>。有几种方法可以解决这个问题:

  1. Cast the result to whatever generic type you expect:

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

    Of course, that will lead to an unchecked cast warning. You can suppress the warning if you want via a @SuppressWarnings("unchecked") annotation but the operation remains unsafe.

  2. Keep your own reference to the TextFormatter<Number> and provide a method for other code to get it.

    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>。这是因为DoubleProperty是一个Property<Number>,而bindBidirectional方法需要精确的泛型匹配,不像bind方法是上界限定的。这也意味着必须使用一个NumberStringConverter


太棒了!还要感谢你指出 Number 和 Double 的问题。这些泛型很棘手! - joshsweaney

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接