JavaFX 2.2 TextField maxlength
With java8u40 we got a new class TextFormatter: one of its main responsibilities is to provide a hook into any change of text input before it gets comitted to the content. In that hook we can accept/reject or even change the proposed change.
The requirement solved in the OP's self-answer is
- the rule: restrict the length of text to shorter than n chars
- the modification: if the rule is violated, keep the last n chars as the input text and remove the excess chars at its start
Using a TextFormatter, this could be implemented like:
// 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:
- modifying a property while listening to its change might lead to unexpected side-effects
- all suggested solutions on the key-level events are broken (they can't handle paste/programatic changes
This is a better way to do the job on a generic text field:
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);
}
}
});
}
Works perfectly, except for that Undo bug.