我正在处理 JavaFX 2.2 项目,但在使用TextField
控件时遇到问题。我想限制用户可以输入每个TextField
. 但是我找不到属性或类似maxlength的东西。Swing中也存在同样的问题,就这样解决了。如何为 JavaFX 2.2 解决它?
9 回答
这是在通用文本字段上完成这项工作的更好方法:
public static void addTextLimiter(final TextField tf, final int maxLength) {
tf.textProperty().addListener(new ChangeListener<String>() {
@Override
public void changed(final ObservableValue<? extends String> ov, final String oldValue, final String newValue) {
if (tf.getText().length() > maxLength) {
String s = tf.getText().substring(0, maxLength);
tf.setText(s);
}
}
});
}
工作完美,除了那个撤消错误。
使用 java8u40,我们得到了一个新类 TextFormatter:它的主要职责之一是在文本输入的任何更改被提交到内容之前提供一个挂钩。在那个钩子中,我们可以接受/拒绝甚至更改提议的更改。
OP的自我回答中解决的要求是
- 规则:将文本长度限制为短于 n 个字符
- 修改:如果违反规则,保留最后n个字符作为输入文本,并在其开头删除多余的字符
使用 TextFormatter,这可以像这样实现:
// here we adjust the new text
TextField adjust = new TextField("scrolling: " + len);
UnaryOperator<Change> modifyChange = c -> {
if (c.isContentChange()) {
int newLength = c.getControlNewText().length();
if (newLength > len) {
// replace the input text with the last len chars
String tail = c.getControlNewText().substring(newLength - len, newLength);
c.setText(tail);
// replace the range to complete text
// valid coordinates for range is in terms of old text
int oldLength = c.getControlText().length();
c.setRange(0, oldLength);
}
}
return c;
};
adjust.setTextFormatter(new TextFormatter(modifyChange));
旁白:
- 在监听其更改的同时修改属性可能会导致意外的副作用
- 所有关于关键级别事件的建议解决方案都已损坏(它们无法处理粘贴/编程更改
您可以执行类似于此处描述的方法的操作:http: //fxexperience.com/2012/02/restricting-input-on-a-textfield/
class LimitedTextField extends TextField {
private final int limit;
public LimitedTextField(int limit) {
this.limit = limit;
}
@Override
public void replaceText(int start, int end, String text) {
super.replaceText(start, end, text);
verify();
}
@Override
public void replaceSelection(String text) {
super.replaceSelection(text);
verify();
}
private void verify() {
if (getText().length() > limit) {
setText(getText().substring(0, limit));
}
}
};
我用来解决我的问题的完整代码是下面的代码。我像 Sergey Grinev 一样扩展了 TextField 类,并添加了一个空的构造函数。为了设置最大长度,我添加了一个 setter 方法。我首先检查然后替换 TextField 中的文本,因为我想禁用插入超过 maxlength 个字符,否则将在 TextField 的末尾插入 maxlength + 1 个字符,并且 TextField 的第一个字符将被删除。
package fx.mycontrols;
public class TextFieldLimited extends TextField {
private int maxlength;
public TextFieldLimited() {
this.maxlength = 10;
}
public void setMaxlength(int maxlength) {
this.maxlength = maxlength;
}
@Override
public void replaceText(int start, int end, String text) {
// Delete or backspace user input.
if (text.equals("")) {
super.replaceText(start, end, text);
} else if (getText().length() < maxlength) {
super.replaceText(start, end, text);
}
}
@Override
public void replaceSelection(String text) {
// Delete or backspace user input.
if (text.equals("")) {
super.replaceSelection(text);
} else if (getText().length() < maxlength) {
// Add characters, but don't exceed maxlength.
if (text.length() > maxlength - getText().length()) {
text = text.substring(0, maxlength- getText().length());
}
super.replaceSelection(text);
}
}
}
在 fxml 文件中,我在文件顶部添加了导入(TextFieldLimited 类存在的包),并将 TextField 标记替换为自定义 TextFieldLimited。
<?import fx.mycontrols.*?>
.
.
.
<TextFieldLimited fx:id="usernameTxtField" promptText="username" />
在控制器类内部,
在顶部(财产声明),
@FXML
private TextFieldLimited usernameTxtField;
在初始化方法中,
usernameTxtField.setLimit(40);
就这样。
我正在使用一种更简单的方法来限制字符数并强制输入数字:
public TextField data;
public static final int maxLength = 5;
data.textProperty().addListener(new ChangeListener<String>() {
@Override
public void changed(ObservableValue<? extends String> observable,
String oldValue, String newValue) {
try {
// force numeric value by resetting to old value if exception is thrown
Integer.parseInt(newValue);
// force correct length by resetting to old value if longer than maxLength
if(newValue.length() > maxLength)
data.setText(oldValue);
} catch (Exception e) {
data.setText(oldValue);
}
}
});
下面的代码将重新定位光标,这样用户就不会意外覆盖他们的输入。
public static void setTextLimit(TextField textField, int length) {
textField.setOnKeyTyped(event -> {
String string = textField.getText();
if (string.length() > length) {
textField.setText(string.substring(0, length));
textField.positionCaret(string.length());
}
});
}
此方法让 TextField 完成所有处理(复制/粘贴/撤消安全)。不需要进行扩展类。并允许您决定每次更改后如何处理新文本(将其推送到逻辑,或返回到先前的值,甚至修改它)。
// fired by every text property change
textField.textProperty().addListener(
(observable, oldValue, newValue) -> {
// Your validation rules, anything you like
// (! note 1 !) make sure that empty string (newValue.equals(""))
// or initial text is always valid
// to prevent inifinity cycle
// do whatever you want with newValue
// If newValue is not valid for your rules
((StringProperty)observable).setValue(oldValue);
// (! note 2 !) do not bind textProperty (textProperty().bind(someProperty))
// to anything in your code. TextProperty implementation
// of StringProperty in TextFieldControl
// will throw RuntimeException in this case on setValue(string) call.
// Or catch and handle this exception.
// If you want to change something in text
// When it is valid for you with some changes that can be automated.
// For example change it to upper case
((StringProperty)observable).setValue(newValue.toUpperCase());
}
);
对于您的情况,只需在其中添加此逻辑即可。完美运行。
// For example 10 characters
if (newValue.length() >= 10) ((StringProperty)observable).setValue(oldValue);
我有这段代码只允许数字并限制Javafx中文本字段的输入长度。
// Event handler for inputPrice
inputPrice.setOnAction(event2 -> {
// Obtain input as a String from text field
String inputPriceStr = inputPrice.getText();
// Get length of the String to compare with max length
int length = inputPrice.getText().length();
final int MAX = 10; // limit number of characters
// Validate user input allowing only numbers and limit input size
if (inputPriceStr.matches("[0-9]*") && length < MAX ) {
// your code here
}});
private void registerListener1(TextField tf1, TextField tf2,TextField tf3,TextField tf4) {
tf1.textProperty().addListener((obs, oldText, newText) -> {
if(newText.length() == 12) {
tf1.setText(newText.substring(0, 3));
tf2.setText(newText.substring(tf1.getText().length(), 6));
tf3.setText(newText.substring(tf1.getText().length()+tf2.getText().length(), 9));
tf4.setText(newText.substring(tf1.getText().length()+tf2.getText().length()+tf3.getText().length()));
tf4.requestFocus();
}
});
}
private void registerListener(TextField tf1, TextField tf2) {
tf1.textProperty().addListener((obs, oldText, newText) -> {
if(oldText.length() < 3 && newText.length() >= 3) {
tf2.requestFocus();
}
});
}