So stellen Sie sicher, dass ein Benutzer gibt nur doppelte Werte ein in einem bestimmten TextField?
Ich habe eine Lösung für ganze Zahlen gefunden, aber ich kann sie nicht für Doubles verwenden. Was soll ich statt dessen schreiben "\\d*"
und "[^\\d]"
damit es für Doppel funktioniert?
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]", ""));
}
}
});
Der Ansatz, einen Listener zu verwenden und zu gültigen Werten zurückzukehren, wenn ungültige Werte vom Benutzer eingegeben werden, funktioniert, kann jedoch zu Problemen führen, wenn Sie andere Listener in den Textfeldern haben textProperty
. Diese Listener werden sowohl die ungültigen als auch die gültigen Werte beobachten, also müssen sie wissen, dass sie alle ungültigen Werte herausfiltern müssen.
Ein besserer Ansatz ist die Verwendung von a TextFormatter
. Das TextFormatter
kann zwei Dinge tun:
- Definieren Sie einen “Filter”, der alle an der vorgenommenen Änderungen ablehnen oder ändern kann
TextField
s Text
- Definieren Sie einen “Konverter”, der definiert, wie der Text in und aus Werten eines bestimmten Typs konvertiert wird (z
Double
) in Ihrem Fall.
Das Definieren des geeigneten Filters kann schwierig sein: Sie möchten alle sinnvollen Änderungen durch den Benutzer zulassen. Das bedeutet, dass der Text möglicherweise in einem ungültigen Zustand ist, während der Benutzer ihn bearbeitet; zB möchten Sie wahrscheinlich zulassen, dass das Textfeld vollständig leer ist, obwohl dies keinen gültigen Wert darstellt. (Andernfalls wird es für den Benutzer ärgerlich, wenn er beispielsweise “1” in “2” ändern möchte.) Ebenso möchten Sie wahrscheinlich Dinge wie “-” und “.” usw. zulassen.
Hier ist ein Beispiel. Der Filter sollte die ihm übergebene Änderung bei Bedarf modifizieren und kann zurückkehren null
einer Änderung vollständig widersprechen. Dieses Beispiel überprüft einfach, ob der Text einen gültigen Bearbeitungsstatus darstellt, und gibt die Änderung unverändert zurück, wenn dies der Fall ist, andernfalls wird dagegen ein Veto eingelegt. Der Formatierer muss jeden Text verarbeiten, der vom Filter zugelassen wird, und ihn in einen Double konvertieren. Hier wird alles, was unvollständig ist, einfach als Null dargestellt.
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);
Sie können den regulären Ausdruck bei Bedarf komplexer machen, z. B. um das Gruppieren von Zeichen zu unterstützen ("1,000.0"
), Lokalisierung ("1.003,14159"
wenn das für das Gebietsschema angemessen ist) oder Darstellungen in wissenschaftlicher Notation ("6.022E23"
usw.) und um Mindest- oder Höchstwerte zu erzwingen usw. Sie können sogar Dinge tun, wie z. B. die Änderung ändern, sodass, wenn der Benutzer a -
An einer beliebigen Stelle im Text wird nur das Vorzeichen der Zahl umgedreht. (Siehe die TextFormatter.Change
Dokumentation für diese Art von Funktionalität.)
Beachten Sie, dass Sie den Double-Wert (wie vom Konverter bereitgestellt) direkt vom Formatierer erhalten und festlegen können, der über eine verfügt ObjectProperty<Double> valueProperty()
. Sie können also Dinge tun wie
// 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());
});
Hier ist ein SSCCE. Das zweite Textfeld ist nur da, damit Sie den Effekt sehen können, wenn der Fokus auf ein anderes Steuerelement verschoben wird (es “übergibt” den Wert und ruft den Listener im Textformatierer auf, wenn sich der Wert geändert hat; Ähnliches passiert, wenn der Benutzer drückt die Eingabetaste).
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);
}
}
Sie könnten Double.parseDouble verwenden Doppeltes Javadoc. Dies übernimmt das Parsen für Sie, anstatt Ihre eigene doppelte Validierung zu schreiben. Sie können dann nach einer Zahlenformat-Ausnahme oder einer Nullzeiger-Ausnahme suchen.
try
{
Double.parseDouble(newValue);
// Valid double
}
catch (NullPointerException | NumberFormatException ex)
{
// Not valid double
}
Sie können den Java-Regex für Doubles verwenden und Zeichen, die keine Zahlen sind, durch Zahlen ersetzen. In müssen Sie die zulässige Anzahl von Stellen im ganzzahligen Teil angeben, zum Beispiel 1,10.
textField.textProperty().addListener(new ChangeListener<String>() {
@Override
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
if (!newValue.matches("[0-9]{<range>}(\\.[0-9]*)?")) {
textField.setText(newValue.replaceAll("[^\\d.]", ""));
StringBuilder aus = new StringBuilder(newValue);
boolean firstPointFound = false;
for (int i = 0; i < aus.length(); i++){
if(aus.charAt(i) == '.') {
if(!firstPointFound)
firstPointFound = true;
else
aus.deleteCharAt(i);
}
}
newValue = aus.toString();
}
}
});
Verwenden Sie keinen Zuhörer; andere Beobachter der Texteigenschaft sehen die ungültige Eingabe, bevor sie zurückgesetzt wird. Benutze einen
TextFormatter
stattdessen.– James_D
31. August 2017 um 12:04 Uhr