如何限制 TextField 使其只能包含一个“.”特点? JavaFX
How to restrict TextField so that it can contain only one '.' character? JavaFX
在网上,我发现非常有用class,使用它我可以限制TextField。我遇到了一个问题,我的 TextField 只能包含一个“.”。特点。我怀疑我可以通过编写适当的正则表达式并将其设置为对该 class 实例的限制来处理这个问题。我使用以下正则表达式:“[0-9.-]”,但它允许的点数与用户键入的点数一样多。我可以请你帮我配置我的 TextField 以便不超过一个 '.'是允许的。
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.control.TextField;
/**
* Created by Anton on 7/14/2015.
*/
public class RestrictiveTextField extends TextField {
private IntegerProperty maxLength = new SimpleIntegerProperty(this, "maxLength", -1);
private StringProperty restrict = new SimpleStringProperty(this, "restrict");
public RestrictiveTextField() {
super("0");
textProperty().addListener(new ChangeListener<String>() {
private boolean ignore;
@Override
public void changed(ObservableValue<? extends String> observableValue, String s, String s1) {
if (ignore || s1 == null)
return;
if (maxLength.get() > -1 && s1.length() > maxLength.get()) {
ignore = true;
setText(s1.substring(0, maxLength.get()));
ignore = false;
}
if (restrict.get() != null && !restrict.get().equals("") && !s1.matches(restrict.get() + "*")) {
ignore = true;
setText(s);
ignore = false;
}
}
});
}
/**
* The max length property.
*
* @return The max length property.
*/
public IntegerProperty maxLengthProperty() {
return maxLength;
}
/**
* Gets the max length of the text field.
*
* @return The max length.
*/
public int getMaxLength() {
return maxLength.get();
}
/**
* Sets the max length of the text field.
*
* @param maxLength The max length.
*/
public void setMaxLength(int maxLength) {
this.maxLength.set(maxLength);
}
/**
* The restrict property.
*
* @return The restrict property.
*/
public StringProperty restrictProperty() {
return restrict;
}
/**
* Gets a regular expression character class which restricts the user input.
*
* @return The regular expression.
* @see #getRestrict()
*/
public String getRestrict() {
return restrict.get();
}
/**
* Sets a regular expression character class which restricts the user input.
* E.g. [0-9] only allows numeric values.
*
* @param restrict The regular expression.
*/
public void setRestrict(String restrict) {
this.restrict.set(restrict);
}
}
您可以使用以下正则表达式,
"[^\.]*\.{0,1}[^\.]"
或者正如 VGR 指出的那样,"A period has no special meaning inside character class brackets and 0 or 1 time can be represented with a '?' (question mark).",所以你也可以使用,
"[^.]*\.?[^.]"
我不知道为什么,但是你的 class 似乎在正则表达式中附加了一个 *
,所以上面的正则表达式将有效地变成,
"[^\.]*\.{0,1}[^\.]*"
也就是说,
- 它将允许除
.
之外的任何字符出现 0 次或更多次(贪心)。
- 它将允许
.
0 或 1 次。
- 它将允许除
.
之外的任何字符出现 0 次或更多次(贪心)。
这似乎是您所需要的。 DEMO
{[0-9]+\.[0-9]+}
匹配任何数字,如果这实际上是您想要做的
正则表达式有多种版本,具体取决于您要支持的内容。请注意,您不仅要匹配有效数字,还要匹配部分条目,因为用户必须能够对其进行编辑。因此,例如,空字符串不是有效数字,但您肯定希望用户能够在编辑时删除其中的所有内容;同样,您希望允许 "0."
,等等
所以你可能想要这样的东西
可选减号,后跟或者任意位数,或至少一位,句点(.
), 和任意数量的数字。
正则表达式可以是 -?((\d*)|(\d+\.\d*))
。可能还有其他方法可以做到这一点,其中一些可能更有效。如果你想支持指数形式("1.3e12"
),它会变得更复杂。
要将其与 TextField
一起使用,推荐的方法是使用 TextFormatter
。 TextFormatter
由两部分组成:一个转换器,用于在文本和它所代表的值之间进行转换(在您的情况下为 Double
:您可以只使用内置的 DoubleStringConverter
),以及反之亦然,然后是过滤器。过滤器被实现为一个函数,它接受一个 TextFormatter.Change
对象和 returns 一个相同类型的对象。通常,您要么保留 Change
对象原样,而 return 它(接受 Change
"as is"),或者以某种方式修改它。 returnnull
代表"no change"也是合法的。因此,在此处的简单情况下,只需检查新提议的文本,看看它是否与正则表达式匹配,return 如果匹配则更改 "as is",否则 return null
。
示例:
import java.util.regex.Pattern;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.control.TextFormatter;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.converter.DoubleStringConverter;
public class NumericTextFieldExample extends Application {
@Override
public void start(Stage primaryStage) {
TextField textField = new TextField();
Pattern validDoubleText = Pattern.compile("-?((\d*)|(\d+\.\d*))");
TextFormatter<Double> textFormatter = new TextFormatter<Double>(new DoubleStringConverter(), 0.0,
change -> {
String newText = change.getControlNewText() ;
if (validDoubleText.matcher(newText).matches()) {
return change ;
} else return null ;
});
textField.setTextFormatter(textFormatter);
textFormatter.valueProperty().addListener((obs, oldValue, newValue) -> {
System.out.println("New double value "+newValue);
});
StackPane root = new StackPane(textField);
root.setPadding(new Insets(24));
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
在网上,我发现非常有用class,使用它我可以限制TextField。我遇到了一个问题,我的 TextField 只能包含一个“.”。特点。我怀疑我可以通过编写适当的正则表达式并将其设置为对该 class 实例的限制来处理这个问题。我使用以下正则表达式:“[0-9.-]”,但它允许的点数与用户键入的点数一样多。我可以请你帮我配置我的 TextField 以便不超过一个 '.'是允许的。
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.control.TextField;
/**
* Created by Anton on 7/14/2015.
*/
public class RestrictiveTextField extends TextField {
private IntegerProperty maxLength = new SimpleIntegerProperty(this, "maxLength", -1);
private StringProperty restrict = new SimpleStringProperty(this, "restrict");
public RestrictiveTextField() {
super("0");
textProperty().addListener(new ChangeListener<String>() {
private boolean ignore;
@Override
public void changed(ObservableValue<? extends String> observableValue, String s, String s1) {
if (ignore || s1 == null)
return;
if (maxLength.get() > -1 && s1.length() > maxLength.get()) {
ignore = true;
setText(s1.substring(0, maxLength.get()));
ignore = false;
}
if (restrict.get() != null && !restrict.get().equals("") && !s1.matches(restrict.get() + "*")) {
ignore = true;
setText(s);
ignore = false;
}
}
});
}
/**
* The max length property.
*
* @return The max length property.
*/
public IntegerProperty maxLengthProperty() {
return maxLength;
}
/**
* Gets the max length of the text field.
*
* @return The max length.
*/
public int getMaxLength() {
return maxLength.get();
}
/**
* Sets the max length of the text field.
*
* @param maxLength The max length.
*/
public void setMaxLength(int maxLength) {
this.maxLength.set(maxLength);
}
/**
* The restrict property.
*
* @return The restrict property.
*/
public StringProperty restrictProperty() {
return restrict;
}
/**
* Gets a regular expression character class which restricts the user input.
*
* @return The regular expression.
* @see #getRestrict()
*/
public String getRestrict() {
return restrict.get();
}
/**
* Sets a regular expression character class which restricts the user input.
* E.g. [0-9] only allows numeric values.
*
* @param restrict The regular expression.
*/
public void setRestrict(String restrict) {
this.restrict.set(restrict);
}
}
您可以使用以下正则表达式,
"[^\.]*\.{0,1}[^\.]"
或者正如 VGR 指出的那样,"A period has no special meaning inside character class brackets and 0 or 1 time can be represented with a '?' (question mark).",所以你也可以使用,
"[^.]*\.?[^.]"
我不知道为什么,但是你的 class 似乎在正则表达式中附加了一个 *
,所以上面的正则表达式将有效地变成,
"[^\.]*\.{0,1}[^\.]*"
也就是说,
- 它将允许除
.
之外的任何字符出现 0 次或更多次(贪心)。 - 它将允许
.
0 或 1 次。 - 它将允许除
.
之外的任何字符出现 0 次或更多次(贪心)。
这似乎是您所需要的。 DEMO
{[0-9]+\.[0-9]+}
匹配任何数字,如果这实际上是您想要做的
正则表达式有多种版本,具体取决于您要支持的内容。请注意,您不仅要匹配有效数字,还要匹配部分条目,因为用户必须能够对其进行编辑。因此,例如,空字符串不是有效数字,但您肯定希望用户能够在编辑时删除其中的所有内容;同样,您希望允许 "0."
,等等
所以你可能想要这样的东西
可选减号,后跟或者任意位数,或至少一位,句点(.
), 和任意数量的数字。
正则表达式可以是 -?((\d*)|(\d+\.\d*))
。可能还有其他方法可以做到这一点,其中一些可能更有效。如果你想支持指数形式("1.3e12"
),它会变得更复杂。
要将其与 TextField
一起使用,推荐的方法是使用 TextFormatter
。 TextFormatter
由两部分组成:一个转换器,用于在文本和它所代表的值之间进行转换(在您的情况下为 Double
:您可以只使用内置的 DoubleStringConverter
),以及反之亦然,然后是过滤器。过滤器被实现为一个函数,它接受一个 TextFormatter.Change
对象和 returns 一个相同类型的对象。通常,您要么保留 Change
对象原样,而 return 它(接受 Change
"as is"),或者以某种方式修改它。 returnnull
代表"no change"也是合法的。因此,在此处的简单情况下,只需检查新提议的文本,看看它是否与正则表达式匹配,return 如果匹配则更改 "as is",否则 return null
。
示例:
import java.util.regex.Pattern;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.control.TextFormatter;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.converter.DoubleStringConverter;
public class NumericTextFieldExample extends Application {
@Override
public void start(Stage primaryStage) {
TextField textField = new TextField();
Pattern validDoubleText = Pattern.compile("-?((\d*)|(\d+\.\d*))");
TextFormatter<Double> textFormatter = new TextFormatter<Double>(new DoubleStringConverter(), 0.0,
change -> {
String newText = change.getControlNewText() ;
if (validDoubleText.matcher(newText).matches()) {
return change ;
} else return null ;
});
textField.setTextFormatter(textFormatter);
textFormatter.valueProperty().addListener((obs, oldValue, newValue) -> {
System.out.println("New double value "+newValue);
});
StackPane root = new StackPane(textField);
root.setPadding(new Insets(24));
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}