it-swarm.com.ru

JavaFX 2.2 TextField maxlength

Я работаю с проектом JavaFX 2.2, и у меня возникла проблема с использованием элемента управления TextField. Я хочу ограничить количество символов, которые пользователи будут вводить для каждого TextField, но я не могу найти свойство или что-то вроде maxlength. Та же самая проблема существовала, чтобы качаться и была решена с этим способом. Как решить это для JavaFX 2.2?

8
George Siggouroglou

Это лучший способ выполнить работу с общим текстовым полем:

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

Работает отлично, за исключением этой ошибки.

13
ceklock

С Java8u40 мы получили новый класс TextFormatter: одна из его основных обязанностей состоит в том, чтобы обеспечить привязку к любому изменению ввода текста до того, как будет добавлено к содержимому. В этом хуке мы можем принять/отклонить t или даже изменить предлагаемое изменение. 

Требование, решенное в ответе ОП 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:

  • изменение свойства при прослушивании его изменения может привести к неожиданным побочным эффектам
  • все предлагаемые решения для событий на уровне ключей не работают (они не могут обрабатывать вставки/программные изменения)
10
kleopatra

Вы можете сделать что-то похожее на подход, описанный здесь: 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));
        }

    }
};
6
Sergey Grinev

Полный код, который я использовал для решения своей проблемы, приведен ниже. Я расширил класс TextField, как это сделал Сергей Гринев, и добавил пустой конструктор. Чтобы установить максимальную длину, я добавил метод установки. Сначала я проверяю, а затем заменяю текст в TextField, потому что я хочу отключить вставку символов, превышающих максимальную длину, в противном случае символ maxlength + 1 будет вставлен в конец TextField, и будет удален первый символ 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);

Это все.

3
George Siggouroglou

Я использую более простой способ ограничения количества символов и принудительного ввода чисел:

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

Этот метод позволяет 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);
1
gmatagmis

Приведенный ниже код переместит курсор, чтобы пользователь случайно не перезаписал свой ввод. 

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());
        }
    });
}
0
Javier Velasquez