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>
。有几种方法可以解决这个问题:
将结果转换为您期望的任何泛型类型:
var formatter = (TextFormatter<Number>) comp.inputField.getTextFormatter();
formatter.valueProperty().bindBidirectional(SomeDataManagerClass.SomeSimpleDoubleProperty());
当然,这会导致出现未经检查的演员表警告。如果需要,您可以通过 @SuppressWarnings("unchecked")
注释抑制警告,但操作仍然不安全。
保留您自己对 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>
。这是因为 DoubleProperty
是 Property<Number>
并且 bindBidirectional
方法需要一个精确的泛型匹配,不像 bind
方法是上限。这也意味着必须使用 NumberStringConverter
。
我有一个 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>
。有几种方法可以解决这个问题:
将结果转换为您期望的任何泛型类型:
var formatter = (TextFormatter<Number>) comp.inputField.getTextFormatter(); formatter.valueProperty().bindBidirectional(SomeDataManagerClass.SomeSimpleDoubleProperty());
当然,这会导致出现未经检查的演员表警告。如果需要,您可以通过
@SuppressWarnings("unchecked")
注释抑制警告,但操作仍然不安全。保留您自己对
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>
。这是因为 DoubleProperty
是 Property<Number>
并且 bindBidirectional
方法需要一个精确的泛型匹配,不像 bind
方法是上限。这也意味着必须使用 NumberStringConverter
。