JavaFX 2.2 текстовое поле maxlength
Я работаю с проектом JavaFX 2.2, и у меня есть проблема с использованием элемента управления TextField. Я хочу ограничить символы, которые пользователи будут вводить в каждое текстовое поле, но я не могу найти свойство или что-то вроде maxlength. Та же проблема существовала, чтобы качаться и была решена с этой путь. Как решить его для JavaFX 2.2?
8 ответов
Это лучший способ выполнить работу с общим текстовым полем:
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: одна из его основных обязанностей-обеспечить крючок в любое изменение ввода текста до он получает comitted к содержанию. В этом крючке мы можем принимаем/reject или даже изменить предлагаемое изменение.
требование, разрешенное в самоответ ОП is
- правило: ограничить длину текста короче, чем 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));
Asides:
- изменение свойства во время прослушивания его изменения может привести к неожиданным побочным эффектам
- все предлагаемые решения на событиях ключевого уровня нарушены (они не могут обрабатывать вставки/программные изменения
вы можете сделать что-то похожее на подход, описанный здесь: 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));
}
}
};
полный код, который я использовал для решения моей проблемы, - это код ниже. Я расширяю класс TextField, как сделал Сергей Гринев, и добавил пустой конструктор. Чтобы установить maxlength, я добавил метод setter. Сначала я проверяю, а затем заменяю текст в текстовом поле, потому что я хочу отключить вставку более символов maxlength, иначе символ maxlength + 1 будет вставлен в конце текстового поля, и первый символ текстового поля будет удаленный.
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;
внутри метода initialize,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);
}
}
});
этот метод позволяет TextField завершить всю обработку (copy/paste/undo safe). Не requares, чтобы сделать расширение класса. И позволит вам решить, что делать с новым текстом после каждого изменения (чтобы подтолкнуть его к логике, или вернуться к предыдущему значению, или даже изменить его).
// 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);
приведенный ниже код переместит курсор, чтобы пользователь случайно не перезаписал свой ввод.
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());
}
});
}
У меня есть этот бит кода, который позволяет только числа и ограничивает длину ввода в текстовом поле в 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
}});