【问题标题】:JavaFX Bind valueProperty from TextField's TextFormatter to SimpleDoublePropertyJavaFX 将 TextField 的 TextFormatter 中的 valueProperty 绑定到 SimpleDoubleProperty
【发布时间】:2020-03-20 05:12:07
【问题描述】:

我有一个 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。但这会返回以下错误:

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?

【问题讨论】:

    标签: java javafx javafx-8


    【解决方案1】:

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

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

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

      当然,这会导致未经检查的强制转换警告。如果需要,您可以通过 @SuppressWarnings("unchecked") 注释取消警告,但操作仍然不安全。

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

      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&lt;Number&gt;。这是因为 DoublePropertyProperty&lt;Number&gt; 并且 bindBidirectional 方法需要精确的泛型匹配,这与有上限的 bind 方法不同。这也意味着必须使用NumberStringConverter

    【讨论】:

    • 太棒了!还要感谢您指出 Number vs. Double 问题。一组棘手的泛型与这些一起使用!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-28
    • 2012-11-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多