Search code examples
javafxfxml

How to limit the amount of characters a javafx textfield


I´m using a FXML to set my form, but I need to set the limit of characters in textfields. How can I made this ?


Solution

  • Here is my solution to limit the length of a textfield. I would not recommend solutions which use a listener (on text property or on length property), they do not behave correctly in all situations (for what I have seen). I create an HTML input text with a max length, and compare it to my textfield in JavaFX. I had the same behavior with paste operations (Ctrl + V), cancel operations (Ctrl + Z) in both cases. The goal here is to check if the text is valid BEFORE modifying the textfield. We could use a similar approach for a numeric text field.

    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);
                }
            }
        }
    }
    

    Tested with JavaFX 8 and Java 8u45