我试图改变TextField
的值仅供显示。即 - 当用户尝试输入电话号码时,他们只输入数字,当他们离开该字段时,它显示格式化而不更改字段中的数据。
假设我有一个电话号码的TextField
,它应该只允许数字,最多10个字符:
2085551212
我可以使用TextFormatter
处理UnaryOperator
。
UnaryOperator<TextFormatter.Change> filter = new UnaryOperator<TextFormatter.Change>() {
@Override
public TextFormatter.Change apply(TextFormatter.Change change) {
int maxlength = 14;
if(change.getControlText().indexOf('(') == -1) {
maxlength = 10;
}
System.out.println(change);
if (change.getControlText().length() + change.getText().length() >= maxlength) {
int maxPos = maxlength - change.getControlText().length();
change.setText(change.getText().substring(0, maxPos));
}
String text = change.getText();
for (int i = 0; i < text.length(); i++)
if (!Character.isDigit(text.charAt(i)))
return null;
return change;
}
};
但是我想将值格式化为10个字符长(当!= 10时可能未格式化):
(208) 555-1212
当我使用TextFormatter
格式化它时,它会将字符串的值更改为(208)555-1212。我们只存储数据库2085551212中的数字。
我用StringConverter
尝试了这个。但我无法使其发挥作用。在toString()
方法中我删除格式,但是当我这样做时,我的TextField
不会显示。
StringConverter<String> formatter = new StringConverter<String>() {
@Override
public String fromString(String string) {
System.out.println("fromString(): before = " + string);
if (string.length() == 14) {
System.out.println("fromString(): after = " + string);
return string;
} else if (string.length() == 10 && string.indexOf('-') == -1) {
String result = String.format("(%s) %s-%s", string.substring(0, 3), string.substring(3, 6),
string.substring(6, 10));
System.out.println("fromString(): after = " + result);
return result;
} else {
return null;
}
}
@Override
public String toString(String object) {
System.out.println("toString(): before = " + object);
if(object == null) {
return "";
}
Pattern p = Pattern.compile("[\\p{Punct}\\p{Blank}]", Pattern.UNICODE_CHARACTER_CLASS);
Matcher m = p.matcher(object);
object = m.replaceAll("");
System.out.println("toString(): after = " + object);
return object;
}
};
我绑定了这样的TextField
,我认为它会起作用:
txtPhone.setTextFormatter(new TextFormatter<String>(formatter, null, filter));
t2.textProperty().bindBidirectional(foo.fooPropertyProperty(), formatter); //I was just testing to see the results in another textfield to see if it would work.
所以我不知所措。我本质上只想允许数字,然后当用户离开字段时以格式化方式显示值 - 而不实际更改进入数据库的字符串值。
你在转换器中混淆了toString()
和fromString()
方法的目的。 toString()
将文本编辑器的value属性转换为显示的文本,而不是相反。尝试在这些方法中切换代码,它应该工作。
失去焦点后文本字段不显示任何内容的原因是因为调用fromString()
方法并返回null(来自else
子句)。这会将null
提交给编辑器的value属性。 value属性的更改通过调用toString(null)
更新显示的文本(textProperty),TextField
将编辑器的text属性更改为空字符串。
编辑
以下是我的测试代码,它是评论中讨论的后续内容。我重复使用了大量的原始代码。我创建了一个FXML JavaFX项目,并在FXML文件中定义了Label
和TextField
。 Label
接受用户的输入并对其进行格式化。 formatter.valueProperty().get()
显示应该转到数据库的文本格式化程序的值(仅限数字)。通过调用import java.net.URL;
import java.util.ResourceBundle;
import java.util.function.UnaryOperator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.control.TextFormatter;
import javafx.util.StringConverter;
public class FXMLDocumentController implements Initializable {
// label displays phone number containing only digits (for database)
@FXML private Label label;
/* field displays formatted text (XXX)-XXX-XXXX after user types
10 digits and presses Enter or if the field looses focus */
@FXML private TextField field;
@Override
public void initialize(URL url, ResourceBundle rb) {
UnaryOperator<TextFormatter.Change> filter = new UnaryOperator<TextFormatter.Change>() {
@Override
public TextFormatter.Change apply(TextFormatter.Change change) {
if (!change.isContentChange()) {
/* nothing is added or deleted but change must be returned
* as it contains selection info and caret position
*/
return change;
}
int maxlength = 14;
if (change.getControlText().indexOf('(') == -1) {
maxlength = 10;
}
if (change.getControlNewText().length() > maxlength
|| change.getText().matches("\\D+")) {
// invalid input. Cancel the change
return null;
}
return change;
}
};
StringConverter<String> converter = new StringConverter<String>() {
// updates displayed text from commited value
@Override
public String toString(String commitedText) {
if (commitedText == null) {
// don't change displayed text
return field.getText();
}
if (commitedText.length() == 10 && !commitedText.matches("\\D+")) {
return String.format("(%s) %s-%s", commitedText.substring(0, 3), commitedText.substring(3, 6),
commitedText.substring(6, 10));
} else {
/* Commited text can be either null or 10 digits.
* Nothing else is allowed by fromString() method unless changed directly
*/
throw new IllegalStateException(
"Unexpected or incomplete phone number value: " + commitedText);
}
}
// commits displayed text to value
@Override
public String fromString(String displayedText) {
// remove formatting characters
Pattern p = Pattern.compile("[\\p{Punct}\\p{Blank}]", Pattern.UNICODE_CHARACTER_CLASS);
Matcher m = p.matcher(displayedText);
displayedText = m.replaceAll("");
if (displayedText.length() != 10) {
// user is not done typing the number. Don't commit
return null;
}
return displayedText;
}
};
TextFormatter<String> formatter = new TextFormatter<String>(converter, "1234567890", filter);
field.setTextFormatter(formatter);
label.textProperty().bind(formatter.valueProperty());
}
}
可以访问该值。我希望它有所帮助。
qazxswpoi