JavaFX:运行 ChangeListener
JavaFX: Run ChangeListener
我可以运行初始化里面ChangeListener
里面的change方法吗。
因为只有 运行 发生变化时。例如,我有一个 TextField
,当它为空时,我想将它的值设置为 0,我这样做是这样的:
textField.textProperty().addListener(new ChangeListener<String>() {
@Override
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
if (!newValue.matches("\d*")) {
textField.setText(newValue.replaceAll("[^\d]", ""));
}
if (newValue.isEmpty())
textField.setText("0");
}
});
但是在应用程序启动时并没有调用更改的方法。那么如何解决这个问题?
无法访问添加到 属性 的侦听器。显然你可以只保留对它的引用:
ChangeListener<String> textFieldListener = (observable, oldValue, newValue) -> {
if (!newValue.matches("\d*")) {
textField.setText(newValue.replaceAll("[^\d]", ""));
}
if (newValue.isEmpty())
textField.setText("0");
};
textField.textProperty().addListener(textFieldListener);
textFieldListener.changed(null, null, textField.getText());
或者,也许更自然地,将实际功能移至不同的方法:
textField.textProperty().addListener((observable, oldValue, newValue) -> vetoTextFieldChanges());
vetoTextFieldChanges();
// ...
private void vetoTextFieldChanges() {
String newText = textField.getText();
if (!newText.matches("\d*")) {
textField.setText(newText.replaceAll("[^\d]", ""));
}
if (newText.isEmpty())
textField.setText("0");
}
请注意,监视更改然后在它们与您的业务逻辑不一致时进行修改的整个方法不是很令人满意。例如,如果您有其他注册了 属性 的侦听器,他们可能会看到文本的中间(无效)值。支持的方法是使用 TextFormatter
。 TextFormatter
既允许您否决请求对文本进行的更改, 在 更新 textProperty()
之前,也可以将文本转换为适当的值。所以在你的情况下你可以这样做:
UnaryOperator<TextFormatter.Change> filter = change -> {
// remove any non-digit characters from inserted text:
if (! change.getText().matches("\d*")) {
change.setText(change.getText().replaceAll("[^\d]", ""));
}
// if new text is empty, replace all text with "0":
if (change.getControlNewText().isEmpty()) {
change.setRange(0, change.getControlText().length());
change.setText("0");
}
return change ;
};
TextFormatter<Integer> formatter = new TextFormatter<Integer>(new IntegerStringConverter(), 0, filter);
textField.setTextFormatter(formatter);
现在您可以使用格式化程序直接通过格式化程序的 value
属性 获取(数字)值,并将它们绑定到您的模型等:
// assume model is a data model and valueProperty() returns a Property<Integer>:
formatter.valueProperty().bindBidirectional(model.valueProperty());
请注意,像这样的绑定将在模型更改时更新格式化程序(以及随后的文本字段),并且还将根据您的模型值对其进行初始化(从而为您的原始问题提供解决方案)。
我可以运行初始化里面ChangeListener
里面的change方法吗。
因为只有 运行 发生变化时。例如,我有一个 TextField
,当它为空时,我想将它的值设置为 0,我这样做是这样的:
textField.textProperty().addListener(new ChangeListener<String>() {
@Override
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
if (!newValue.matches("\d*")) {
textField.setText(newValue.replaceAll("[^\d]", ""));
}
if (newValue.isEmpty())
textField.setText("0");
}
});
但是在应用程序启动时并没有调用更改的方法。那么如何解决这个问题?
无法访问添加到 属性 的侦听器。显然你可以只保留对它的引用:
ChangeListener<String> textFieldListener = (observable, oldValue, newValue) -> {
if (!newValue.matches("\d*")) {
textField.setText(newValue.replaceAll("[^\d]", ""));
}
if (newValue.isEmpty())
textField.setText("0");
};
textField.textProperty().addListener(textFieldListener);
textFieldListener.changed(null, null, textField.getText());
或者,也许更自然地,将实际功能移至不同的方法:
textField.textProperty().addListener((observable, oldValue, newValue) -> vetoTextFieldChanges());
vetoTextFieldChanges();
// ...
private void vetoTextFieldChanges() {
String newText = textField.getText();
if (!newText.matches("\d*")) {
textField.setText(newText.replaceAll("[^\d]", ""));
}
if (newText.isEmpty())
textField.setText("0");
}
请注意,监视更改然后在它们与您的业务逻辑不一致时进行修改的整个方法不是很令人满意。例如,如果您有其他注册了 属性 的侦听器,他们可能会看到文本的中间(无效)值。支持的方法是使用 TextFormatter
。 TextFormatter
既允许您否决请求对文本进行的更改, 在 更新 textProperty()
之前,也可以将文本转换为适当的值。所以在你的情况下你可以这样做:
UnaryOperator<TextFormatter.Change> filter = change -> {
// remove any non-digit characters from inserted text:
if (! change.getText().matches("\d*")) {
change.setText(change.getText().replaceAll("[^\d]", ""));
}
// if new text is empty, replace all text with "0":
if (change.getControlNewText().isEmpty()) {
change.setRange(0, change.getControlText().length());
change.setText("0");
}
return change ;
};
TextFormatter<Integer> formatter = new TextFormatter<Integer>(new IntegerStringConverter(), 0, filter);
textField.setTextFormatter(formatter);
现在您可以使用格式化程序直接通过格式化程序的 value
属性 获取(数字)值,并将它们绑定到您的模型等:
// assume model is a data model and valueProperty() returns a Property<Integer>:
formatter.valueProperty().bindBidirectional(model.valueProperty());
请注意,像这样的绑定将在模型更改时更新格式化程序(以及随后的文本字段),并且还将根据您的模型值对其进行初始化(从而为您的原始问题提供解决方案)。