我需要限制一个TextField输入整数,有什么建议吗?
虽然这个帖子非常古老,但是这种方法看起来更整洁,并且可以去除复制过来的非数字字符。
// force the field to be numeric only
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]", ""));
}
}
});
\\D+
(或只是 \\D
)代替 [^\\d]
。 - ricky3350double
,那么我应该写什么而不是\\d*
和[^\\d]
?@EvanKnowles - Robb1Integer.parseInt(newValue)
,并使用 try
和 catch
来捕获 NumberFormatException
错误。 - user1300214javafx.scene.control.TextFormatter
更新于2016年4月
这篇答案是几年前创建的,原始答案现在基本已经过时。
自Java 8u40以来,Java有一个TextFormatter,通常最适合强制执行特定格式的输入,例如在JavaFX TextFields上的数字:
还可以查看此问题的其他答案,其中明确提到了TextFormatter。
原始答案
在这个代码片段中有一些示例,我在下面复制了一个示例:
// helper text field subclass which restricts text input to a given range of natural int numbers
// and exposes the current numeric int value of the edit box as a value property.
class IntField extends TextField {
final private IntegerProperty value;
final private int minValue;
final private int maxValue;
// expose an integer value property for the text field.
public int getValue() { return value.getValue(); }
public void setValue(int newValue) { value.setValue(newValue); }
public IntegerProperty valueProperty() { return value; }
IntField(int minValue, int maxValue, int initialValue) {
if (minValue > maxValue)
throw new IllegalArgumentException(
"IntField min value " + minValue + " greater than max value " + maxValue
);
if (!((minValue <= initialValue) && (initialValue <= maxValue)))
throw new IllegalArgumentException(
"IntField initialValue " + initialValue + " not between " + minValue + " and " + maxValue
);
// initialize the field values.
this.minValue = minValue;
this.maxValue = maxValue;
value = new SimpleIntegerProperty(initialValue);
setText(initialValue + "");
final IntField intField = this;
// make sure the value property is clamped to the required range
// and update the field's text to be in sync with the value.
value.addListener(new ChangeListener<Number>() {
@Override public void changed(ObservableValue<? extends Number> observableValue, Number oldValue, Number newValue) {
if (newValue == null) {
intField.setText("");
} else {
if (newValue.intValue() < intField.minValue) {
value.setValue(intField.minValue);
return;
}
if (newValue.intValue() > intField.maxValue) {
value.setValue(intField.maxValue);
return;
}
if (newValue.intValue() == 0 && (textProperty().get() == null || "".equals(textProperty().get()))) {
// no action required, text property is already blank, we don't need to set it to 0.
} else {
intField.setText(newValue.toString());
}
}
}
});
// restrict key input to numerals.
this.addEventFilter(KeyEvent.KEY_TYPED, new EventHandler<KeyEvent>() {
@Override public void handle(KeyEvent keyEvent) {
if(intField.minValue<0) {
if (!"-0123456789".contains(keyEvent.getCharacter())) {
keyEvent.consume();
}
}
else {
if (!"0123456789".contains(keyEvent.getCharacter())) {
keyEvent.consume();
}
}
}
});
// ensure any entered values lie inside the required range.
this.textProperty().addListener(new ChangeListener<String>() {
@Override public void changed(ObservableValue<? extends String> observableValue, String oldValue, String newValue) {
if (newValue == null || "".equals(newValue) || (intField.minValue<0 && "-".equals(newValue))) {
value.setValue(0);
return;
}
final int intValue = Integer.parseInt(newValue);
if (intField.minValue > intValue || intValue > intField.maxValue) {
textProperty().setValue(oldValue);
}
value.set(Integer.parseInt(textProperty().get()));
}
});
}
}
我知道这是一个相当古老的帖子,但是为了未来的读者,这里有另一个我认为非常直观的解决方案:
public class NumberTextField extends TextField
{
@Override
public void replaceText(int start, int end, String text)
{
if (validate(text))
{
super.replaceText(start, end, text);
}
}
@Override
public void replaceSelection(String text)
{
if (validate(text))
{
super.replaceSelection(text);
}
}
private boolean validate(String text)
{
return text.matches("[0-9]*");
}
}
text.matches("\\d+");
但我无法删除文本字段中的任何字符。 - mils从JavaFX 8u40开始,您可以在文本字段上设置TextFormatter对象:
UnaryOperator<Change> filter = change -> {
String text = change.getText();
if (text.matches("[0-9]*")) {
return change;
}
return null;
};
TextFormatter<String> textFormatter = new TextFormatter<>(filter);
fieldNport = new TextField();
fieldNport.setTextFormatter(textFormatter);
这样做既避免了子类化,也避免了重复的更改事件。如果您向文本属性添加更改侦听器并在该侦听器中修改文本,则会出现这些问题。
TextInput
有一个TextFormatter
,可用于格式化、转换和限制输入文本的类型。
TextFormatter
具有过滤器,可用于拒绝输入。我们需要将其设置为拒绝任何无效的整数。它还具有转换器,我们需要将其设置为将字符串值转换为稍后可以绑定的整数值。
让我们创建一个可重复使用的过滤器:
public class IntegerFilter implements UnaryOperator<TextFormatter.Change> {
private final static Pattern DIGIT_PATTERN = Pattern.compile("\\d*");
@Override
public Change apply(TextFormatter.Change aT) {
return DIGIT_PATTERN.matcher(aT.getText()).matches() ? aT : null;
}
}
过滤器可以做三件事情之一,它可以无修改地返回更改以接受它,它可以以某种方式改变更改并认为它合适,或者它可以返回null
,以完全拒绝更改。
我们将使用标准的IntegerStringConverter
作为转换器。
将所有东西放在一起:
TextField textField = ...;
TextFormatter<Integer> formatter = new TextFormatter<>(
new IntegerStringConverter(), // Standard converter form JavaFX
defaultValue,
new IntegerFilter());
formatter.valueProperty().bindBidirectional(myIntegerProperty);
textField.setTextFormatter(formatter);
如果你不需要一个可重复使用的过滤器,你可以用这个花式一行代码替代它:
TextFormatter<Integer> formatter = new TextFormatter<>(
new IntegerStringConverter(),
defaultValue,
c -> Pattern.matches("\\d*", c.getText()) ? c : null );
我不喜欢异常,因此我使用了String类中的matches
函数。
text.textProperty().addListener(new ChangeListener<String>() {
@Override
public void changed(ObservableValue<? extends String> observable, String oldValue,
String newValue) {
if (newValue.matches("\\d*")) {
int value = Integer.parseInt(newValue);
} else {
text.setText(oldValue);
}
}
});
textField.positionCaret(textField.getLength());
- hssonif (newValue.matches("\\d*") && newValue.getText().length < 5)
。 - Quatsch从Java SE 8u40开始,您可以使用一个"integer"Spinner
来安全地通过键盘的上箭头/下箭头键或提供的按钮选择有效整数。
您还可以定义最小值、最大值和初始值以限制允许的值,并指定每步增加或减少的数量。
例如:
// Creates an integer spinner with 1 as min, 10 as max and 2 as initial value
Spinner<Integer> spinner1 = new Spinner<>(1, 10, 2);
// Creates an integer spinner with 0 as min, 100 as max and 10 as initial
// value and 10 as amount to increment or decrement by, per step
Spinner<Integer> spinner2 = new Spinner<>(0, 100, 10, 10);
使用"整数"和"双精度浮点数"微调器的结果示例。
微调器是一种单行文本字段控件,允许用户从有序序列中选择数字或对象值。 微调器通常提供一对微小的箭头按钮,用于逐个步进顺序中的元素。 键盘的上箭头/下箭头键也可以循环遍历元素。 用户还可以直接输入(合法)值到微调器中。 尽管组合框提供类似的功能,但微调器有时更受青睐,因为它们不需要可能会遮挡重要数据的下拉列表,并且还允许功能,例如从最大值回到最小值进行包装(例如,从最大正整数到0)。
如果您使用Java 1.8 Lambda表达式,首选答案甚至可以更小。
textfield.textProperty().addListener((observable, oldValue, newValue) -> {
if (newValue.matches("\\d*")) return;
textfield.setText(newValue.replaceAll("[^\\d]", ""));
});
我想借助Evan Knowles的回答和JavaFX 8中的TextFormatter
来帮助您实现我的想法。
textField.setTextFormatter(new TextFormatter<>(c -> {
if (!c.getControlNewText().matches("\\d*"))
return null;
else
return c;
}
));
祝你好运;保持冷静,编写Java代码。
TextField text = new TextField();
text.textProperty().addListener(new ChangeListener<String>() {
@Override
public void changed(ObservableValue<? extends String> observable,
String oldValue, String newValue) {
try {
Integer.parseInt(newValue);
if (newValue.endsWith("f") || newValue.endsWith("d")) {
manualPriceInput.setText(newValue.substring(0, newValue.length()-1));
}
} catch (ParseException e) {
text.setText(oldValue);
}
}
});
< p>if< /p>子句对于处理像0.5d或0.7f这样的输入非常重要,这些输入通过Int.parseInt()正确解析,但不应出现在文本字段中。