如何在JavaFX的TextField中强制进行双重输入? [英] How to force a double input in a TextField in JavaFX?
问题描述
如何确保用户在给定的TextField中仅输入双精度值?
我找到了解决方案整数 bu我无法将其用于双打.我应该写什么而不是"\\d*"
和"[^\\d]"
来使它适用于双打?
I found a solution for integers bu I can't manage to use it for doubles. What should I write instead of the "\\d*"
and "[^\\d]"
to make it work for doubles?
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]", ""));
}
}
});
推荐答案
使用侦听器并在用户输入无效值时还原为有效值的方法是可行的,但是如果您使用其他侦听器,则可能会产生问题.文本字段的textProperty
.这些侦听器将观察到无效值和有效值,因此他们必须知道要过滤掉所有无效值.
The approach of using a listener and reverting to valid values if invalid values are input by the user will work, but it can create issues if you have other listeners on the text field's textProperty
. Those listeners will observe the invalid values as well as the valid ones, so they have to know to filter out any invalid values.
一种更好的方法是使用 TextFormatter
. TextFormatter
可以做两件事:
A better approach is to use a TextFormatter
. The TextFormatter
can do two things:
- 定义过滤器",该过滤器可以否决或修改对
TextField
文本所做的任何更改 - 定义一个转换器",它定义了如何根据您的情况在文本之间来回转换任何特定类型的值(例如
Double
).
- Define a "Filter", which can veto, or modify, any changes made to the
TextField
's text - Define a "converter", which defines how to convert the text to and from values of any specific type (e.g.
Double
) in your case.
定义适当的过滤器可能很棘手:您希望允许用户进行任何合理的编辑.这意味着在用户编辑时文本可能处于无效状态;例如您可能希望允许文本字段完全为空,即使该字段不代表有效值也是如此. (否则,如果用户想要将"1"更改为"2",这将使用户感到烦恼.)同样,您可能希望允许使用-"和."等内容.
Defining the appropriate filter can be tricky: you want to allow any reasonable edits by the user. This means the text may be in an invalid state while the user is editing; e.g. you probably want to allow the text field to be completely empty, even though that does not represent a valid value. (Otherwise, it becomes annoying to the user if, for example, they want to change "1" to "2".) Similarly you probably want to allow things like "-" and ".", etc.
这里是一个例子.过滤器应根据需要修改传递给它的更改,并且可以返回null
完全否决更改.此示例仅检查文本是否表示有效的编辑状态,然后返回未修改的更改,否则将其否决.格式化程序需要处理过滤器允许的任何文本并将其转换为double.在这里,任何不完整的内容都将表示为零.
Here is an example. The filter should modify the change that is passed to it, if needed, and can return null
to completely veto a change. This example simply checks if the text represents a valid editing state, and returns the change unmodified if it does, vetoing it otherwise. The formatter needs to deal with any text that is allowed by the filter and convert it to a double. Here anything that is incomplete is just represented as zero.
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
文档的功能.)
You can make the regular expression more complex if needed, e.g. to support grouping characters ("1,000.0"
), localization ("1.003,14159"
if that is appropriate for the locale), or scientific-notation-like representations ("6.022E23"
, etc), and to enforce minimum or maximum values, etc. You can even do things such as modifying the change, so that if the user types a -
anywhere in the text, it just flips the sign of the number. (Refer to the TextFormatter.Change
documentation for that kind of functionality.)
请注意,您可以直接从具有ObjectProperty<Double> valueProperty()
的格式化程序获取并设置double值(由转换器提供).所以你可以做类似的事情
Note you can get and set the double value (as provided by the converter) directly from the formatter, which has an ObjectProperty<Double> valueProperty()
. So you can do things like
// 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.第二个文本字段就在那里,因此您可以看到将焦点移到另一个控件上的效果(如果值已更改,它将提交"值并在文本格式化程序上调用侦听器;如果用户更改了类似的内容,按Enter键.
Here is a SSCCE. The second text field is just there so that you can see the effect of moving focus to a different control (it "commits" the value and invokes the listener on the text formatter, if the value has changed; a similar thing happens if the user presses enter).
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);
}
}
这篇关于如何在JavaFX的TextField中强制进行双重输入?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!