【发布时间】:2014-03-28 13:29:04
【问题描述】:
我正在使用 FXML 来设置我的表单,但我需要设置文本字段中的字符限制。我怎样才能做到这一点?
【问题讨论】:
我正在使用 FXML 来设置我的表单,但我需要设置文本字段中的字符限制。我怎样才能做到这一点?
【问题讨论】:
您不能直接设置字符数限制。但是您可以在文本字段的lengthProperty() 中添加listener
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class TextFieldLimit extends Application {
private static final int LIMIT = 10;
public static void main(String[] args) {
launch(args);
}
@Override
public void start(final Stage primaryStage) {
final TextField textField = new TextField();
textField.lengthProperty().addListener(new ChangeListener<Number>() {
@Override
public void changed(ObservableValue<? extends Number> observable,
Number oldValue, Number newValue) {
if (newValue.intValue() > oldValue.intValue()) {
// Check if the new character is greater than LIMIT
if (textField.getText().length() >= LIMIT) {
// if it's 11th character then just setText to previous
// one
textField.setText(textField.getText().substring(0, LIMIT));
}
}
}
});
VBox vbox = new VBox(20);
vbox.getChildren().add(textField);
Scene scene = new Scene(vbox, 400, 300);
primaryStage.setScene(scene);
primaryStage.show();
}
}
【讨论】:
textField.setText(textField.getText().substring(0, LIMIT));。否则,如果用户使用复制和粘贴在其中转储一个非常大的字符串,它将重复调用侦听器,一次减少一个字符。
更优雅的解决方案
Pattern pattern = Pattern.compile(".{0,25}");
TextFormatter formatter = new TextFormatter((UnaryOperator<TextFormatter.Change>) change -> {
return pattern.matcher(change.getControlNewText()).matches() ? change : null;
});
textField.setTextFormatter(formatter);
其中 0 和 25 - 最小和最大字符数。 + 设置输入文本模式的能力
【讨论】:
这是我限制文本字段长度的解决方案。 我不会推荐使用侦听器(在 text 属性或 length 属性上)的解决方案,它们在所有情况下都不能正确运行(就我所见)。 我创建了一个最大长度的 HTML 输入文本,并将其与我在 JavaFX 中的文本字段进行比较。在这两种情况下,我对粘贴操作 (Ctrl + V)、取消操作 (Ctrl + Z) 的行为相同。这里的目标是在修改文本字段之前检查文本是否有效。 我们可以对数字文本字段使用类似的方法。
import java.util.Objects;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.scene.control.TextField;
public class LimitedTextField extends TextField {
private final IntegerProperty maxLength;
public LimitedTextField() {
super();
this.maxLength = new SimpleIntegerProperty(-1);
}
public IntegerProperty maxLengthProperty() {
return this.maxLength;
}
public final Integer getMaxLength() {
return this.maxLength.getValue();
}
public final void setMaxLength(Integer maxLength) {
Objects.requireNonNull(maxLength, "Max length cannot be null, -1 for no limit");
this.maxLength.setValue(maxLength);
}
@Override
public void replaceText(int start, int end, String insertedText) {
if (this.getMaxLength() <= 0) {
// Default behavior, in case of no max length
super.replaceText(start, end, insertedText);
}
else {
// Get the text in the textfield, before the user enters something
String currentText = this.getText() == null ? "" : this.getText();
// Compute the text that should normally be in the textfield now
String finalText = currentText.substring(0, start) + insertedText + currentText.substring(end);
// If the max length is not excedeed
int numberOfexceedingCharacters = finalText.length() - this.getMaxLength();
if (numberOfexceedingCharacters <= 0) {
// Normal behavior
super.replaceText(start, end, insertedText);
}
else {
// Otherwise, cut the the text that was going to be inserted
String cutInsertedText = insertedText.substring(
0,
insertedText.length() - numberOfexceedingCharacters
);
// And replace this text
super.replaceText(start, end, cutInsertedText);
}
}
}
}
使用 JavaFX 8 和 Java 8u45 测试
【讨论】:
我使用一个简单的 ChangeListener 调用来测试执行停止的条件。
textFild.addListener((observable, oldValue, newValue) -> {
if (newValue.length() == MAX_SIZE) {
textField.setText(oldValue);
}
});
【讨论】:
这是一个非常简单的解决方案,似乎对我有用。
textfield.setOnKeyTyped(event ->{
int maxCharacters = 5;
if(tfInput.getText().length() > maxCharacters) event.consume();
});
【讨论】:
这是一个行之有效的解决方案:
@FXML
void limitTextFields(KeyEvent event) {
int maxLength = 5;
TextField tf = (TextField) event.getSource();
if (tf.getText().length() > maxLength) {
tf.deletePreviousChar();
}
}
【讨论】:
这是在通用文本字段上完成这项工作的更好方法:
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); } } }); }
完美运行,除了那个 Undo 错误。
【讨论】:
下面的 1-liner 可以做到这一点,而 5 是 TextField tf 的限制:
tf.setTextFormatter(new TextFormatter<>(c -> c.getControlNewText().matches(".{0,5}") ? c : null));
【讨论】: