使用監聽器,並恢復到有效的值,如果無效值是由用戶輸入將工作的方法,但是如果你對文本字段的textProperty
其他聽衆它可以創造的問題。那些聽衆將觀察無效值和有效值,因此他們必須知道過濾掉任何無效值。
更好的方法是使用TextFormatter
。該TextFormatter
可以做兩兩件事:
- 定義一個「過濾器」,它可以否決或修改,到
TextField
的文本所做的任何更改
- 定義一個‘轉換器’,它定義瞭如何轉換文本與任何特定類型的值(例如
Double
)在您的案例中。
定義適當的過濾器可能會很棘手:您希望允許用戶進行任何合理的編輯。這意味着用戶正在編輯時文本可能處於無效狀態;例如您可能希望允許文本字段完全爲空,即使這不代表有效值。 (否則,例如,如果他們想要將「1」更改爲「2」,則變得煩人)。類似地,您可能希望允許諸如「 - 」和「。」等的東西。
這裏就是一個例子。如果需要,過濾器應修改傳遞給它的更改,並且可以返回null
以完全否決更改。這個例子簡單地檢查文本是否代表一個有效的編輯狀態,如果是,則返回未修改的變化,否則否決。格式化程序需要處理過濾器允許的任何文本並將其轉換爲雙精度。這裏任何不完整的東西都表示爲零。
Pattern validEditingState = Pattern.compile("-?(([1-9][0-9]*)|0)?(\\.[0-9]*)?");
UnaryOperator<TextFormatter.Change> filter = c -> {
String text = c.getControlNewText();
if (validEditingState.matcher(text).matches()) {
return c ;
} else {
return null ;
}
};
StringConverter<Double> converter = new StringConverter<Double>() {
@Override
public Double fromString(String s) {
if (s.isEmpty() || "-".equals(s) || ".".equals(s) || "-.".equals(s)) {
return 0.0 ;
} else {
return Double.valueOf(s);
}
}
@Override
public String toString(Double d) {
return d.toString();
}
};
TextFormatter<Double> textFormatter = new TextFormatter<>(converter, 0.0, filter);
TextField textField = new TextField();
textField.setTextFormatter(textFormatter);
如果需要,您可以使正則表達式更加複雜,例如,以支持分組字符("1,000.0"
),本地化("1.003,14159"
,如果這適合於語言環境)或科學記數法表示("6.022E23"
等),並強制執行最小或最大值等。您甚至可以執行諸如修改該更改,以便如果用戶在文本的任何位置鍵入-
,則只需翻轉該號碼的符號即可。 (請參閱TextFormatter.Change
documentation這種功能。)
請注意,您可以直接從格式化程序獲取並設置double值(由轉換程序提供),該格式化程序具有ObjectProperty<Double> valueProperty()
。所以你可以做像
// update text field:
double value = ... ;
textFormatter.setValue(value);
// listen for changes in double value represented in text field
// Listener will be invoked when the user commits an edit:
textFormatter.valueProperty().addListener((ObservableValue<? extends Double> obs, Double oldValue, Double newValue) -> {
System.out.println("User entered value: "+newValue.doubleValue());
});
這是一個SSCCE。第二個文本字段就在那裏,以便您可以看到將焦點移動到不同控件的效果(如果值已更改,則會「提交」該值並調用文本格式器上的偵聽器;如果用戶出現類似的情況按下進入)。
import java.util.function.UnaryOperator;
import java.util.regex.Pattern;
import javafx.application.Application;
import javafx.beans.value.ObservableValue;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.control.TextFormatter;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.StringConverter;
public class NumericTextField extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
Pattern validEditingState = Pattern.compile("-?(([1-9][0-9]*)|0)?(\\.[0-9]*)?");
UnaryOperator<TextFormatter.Change> filter = c -> {
String text = c.getControlNewText();
if (validEditingState.matcher(text).matches()) {
return c ;
} else {
return null ;
}
};
StringConverter<Double> converter = new StringConverter<Double>() {
@Override
public Double fromString(String s) {
if (s.isEmpty() || "-".equals(s) || ".".equals(s) || "-.".equals(s)) {
return 0.0 ;
} else {
return Double.valueOf(s);
}
}
@Override
public String toString(Double d) {
return d.toString();
}
};
TextFormatter<Double> textFormatter = new TextFormatter<>(converter, 0.0, filter);
TextField textField = new TextField();
textField.setTextFormatter(textFormatter);
textFormatter.valueProperty().addListener((ObservableValue<? extends Double> obs, Double oldValue, Double newValue) -> {
System.out.println("User entered value: "+newValue.doubleValue());
});
VBox root = new VBox(5, textField, new TextField());
root.setAlignment(Pos.CENTER);
primaryStage.setScene(new Scene(root, 250, 250));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
不要使用偵聽器;文本屬性的其他觀察者將在恢復之前看到無效輸入。改用'TextFormatter'。 –