3.5.2.1.47. TextField

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

XML-имя компонента: textField

  • Пример текстового поля с заголовком, взятым из пакета локализованных сообщений:

    <textField id="nameField" caption="msg://name"/>

    На рисунке ниже показан вид простого текстового поля.

    gui textField data
  • В веб-клиенте с темой, основанной на Halo, к компоненту TextField можно применить предопределенные стили. Стили задаются в XML-дексрипторе или контроллере экрана с помощью атрибута stylename:

    <textField id="textField"
               stylename="borderless"/>

    Чтобы применить стиль программно, выберите одну из констант класса HaloTheme с префиксом компонента TEXTFIELD_:

    textField.setStyleName(HaloTheme.TEXTFIELD_INLINE_ICON);

    Стили компонента TextField:

    • align-center - выравние текста по центру поля.

    • align-right - выравнивание текста по правому краю поля.

    • borderless - удаляет рамку и фон текстового поля.

    • inline-icon - расположение значка внутри текстового поля.

    Компонент TextField поддерживает автоматическую конвертацию регистра. Атрибут caseConvertion может принимать следующие значения:

    • UPPER - верхний регистр,

    • LOWER - нижний регистр,

    • NONE - конвертация отключена (значение по умолчанию). Используйте это значение для поддержки клавиатурного ввода с использованием IME, к примеру, для японского, корейского и китайского языков.

  • Для создания текстового поля, связанного с данными, необходимо использовать атрибуты dataContainer и property.

    <data>
        <instance id="customerDc" class="com.company.sales.entity.Customer" view="_local">
            <loader/>
        </instance>
    </data>
    <layout>
        <textField dataContainer="customerDc" property="name" caption="msg://name"/>
    </layout>

    Как видно из примера, в экране описывается контейнер данных customerDs для некоторой сущности Покупатель (Customer), имеющей атрибут name. В компоненте текстового поля в атрибуте dataContainer указывается ссылка на контейнер, а в атрибуте property − название атрибута сущности, значение которого должно быть отображено в текстовом поле.

  • Если поле не связано с атрибутом сущности (то есть не указан контейнер данных и название атрибута), то можно указать тип данных с помощью атрибута datatype. Тип данных используется для форматирования значения поля. В качестве значения атрибута может быть указано любое имя типа данных, зарегистрированного в метаданных приложения – см. Datatype. Как правило, в TextField используются следующие типы данных:

    • decimal

    • double

    • int

    • long

    Если для поля указан атрибут datatype, при вводе некорректного значения появляется стандартное сообщение об ошибке конвертации.

    В качестве примера рассмотрим текстовое поле с типом данных Integer.

    <textField id="integerField" datatype="int" caption="msg://integerFieldName"/>

    Если в таком поле ввести значение, которое невозможно интерпретировать как целое число, то при потере фокуса полем будет выведено стандартное сообщение об ошибке.

    gui datatype default message

    Стандартные сообщения об ошибках конвертации задаются в главном пакете локализованных сообщений и имеют следующий шаблон: databinding.conversion.error.<type>, например:

    databinding.conversion.error.int = Must be Integer
  • Вы можете определять пользовательские сообщения об ошибках конвертации декларативно, используя атрибут conversionErrorMessage в XML-дескрипторе:

    <textField conversionErrorMessage="This field can work only with Integers" datatype="int"/>

    или программно в контроллере экрана:

    textField.setConversionErrorMessage("This field can work only with Integers");
  • Текстовому полю может быть назначен валидатор - класс, реализующий интерфейс Field.Validator. Валидатор позволяет дополнительно к datatype ограничить вводимую пользователем информацию. Например, для создания поля ввода положительных целых чисел нужно создать класс валидатора:

    public class PositiveIntegerValidator implements Field.Validator {
        @Override
        public void validate(Object value) throws ValidationException {
            Integer i = (Integer) value;
            if (i <= 0)
                throw new ValidationException("Value must be positive");
        }
    }

    и задать его для текстового поля с типом данных int в элементе validator:

    <textField id="integerField" datatype="int">
        <validator class="com.sample.sales.gui.PositiveIntegerValidator"/>
    </textField>

    В отличие от проверки вводимой строки на соответствие типу данных, валидация срабатывает не сразу при потере полем фокуса, а только при вызове у поля метода validate(). Это означает, что поле (и связанный с ним атрибут сущности) может некоторое время содержать значение, не удовлетворяющее условиям валидации (в приведенном примере неположительное число). Это не является проблемой, так как обычно поля редактирования с валидацией располагаются в экране редактирования, а он автоматически вызывает валидацию всех своих полей перед коммитом. Если же поле находится не в экране редактирования, то необходимо вызывать метод validate() поля в контроллере явно.

  • Компонент TextField поддерживает слушатель TextChangeListener, определённый в родительском интерфейсе TextInputField. События изменения текста обрабатываются асинхронно после ввода, не блокируя сам ввод.

    textField.addTextChangeListener(event -> {
        int length = event.getText().length();
        textFieldLabel.setValue(length + " of " + textField.getMaxLength());
    });
    textField.setTextChangeEventMode(TextInputField.TextChangeEventMode.LAZY);
    gui textfield 2
  • Параметром TextChangeEventMode задаётся режим передачи изменений на сервер для вызова события на серверной стороне. В платформе реализовано 3 режима передачи:

    • LAZY (по умолчанию) - событие вызывается во время паузы в наборе текста. Продолжительность паузы можно задать с помощью метода setInputEventTimeout(). Событие изменения текста обрабатывается принудительно перед возможным событием ValueChangeEvent, даже если пользователь не выдержал паузу в наборе текста.

    • TIMEOUT - событие вызывается после периода ожидания. В случае ввода нескольких изменений за один период, на сервер отсылается событие со всеми изменениями, включая последнее. Продолжительность периода ожидания можно задать с помощью метода setInputEventTimeout().

      В случае, если ValueChangeEvent может случиться до истечения периода ожидания, событие TextChangeEvent обрабатывается до его истечения, при условии, что набранный текст был изменён после предыдущего TextChangeEvent.

    • EAGER - событие вызывается незамедлительно после каждого изменения текста, то есть после каждого нажатия клавиш. Запросы отправляются по отдельности и обрабатываются последовательно один за другим. Тем не менее, асинхронная передача событий изменения на сервер позволяет не блокировать дальнейший ввод текста.

  • EnterPressListener позволяет указать действие, которое должно быть выполнено по нажатию клавиши Enter:

    textField.addEnterPressListener(enterPressEvent ->
            notifications.create()
                    .withCaption("Enter pressed")
                    .show());
  • ValueChangeListener позволяет обрабатывать изменения значения в текстовом поле, когда пользователь уже закончил ввод, т.е. после нажатия клавиши Enter или при потере компонентом фокуса. В слушатель передается объект события типа ValueChangeEvent, который имеет следующие методы:

    • getPrevValue() возвращает значение компонента до изменения.

    • getValue() возвращает текущее значение компонента.

      textField.addValueChangeListener(stringValueChangeEvent ->
              notifications.create()
                      .withCaption("Before: " + stringValueChangeEvent.getPrevValue() +
                              ". After: " + stringValueChangeEvent.getValue())
                      .show());

      Источник события ValueChangeEvent можно отследить с помощью метода isUserOriginated().

  • Если текстовое поле связано с атрибутом сущности (через datasource и property), и если для атрибута сущности в JPA-аннотации @Column указан параметр length, то TextField будет соответственно ограничивать максимальную длину вводимого текста.

    Если текстовое поле не связано с атрибутом, либо для него не определено значение length, либо это значение нужно переопределить, то для ограничения максимальной длины вводимого текста можно использовать атрибут maxLength. Значение "-1" означает отсутствие ограничения. Например:

    <textField id="shortTextField" maxLength="10"/>
  • По умолчанию текстовое поле отсекает пробелы в начале и конце введенной строки. То есть если пользователь ввел строку " aaa bbb " то значением поля, возвращаемым методом getValue() и сохраняемым в связанный атрибут сущности, будет строка "aaa bbb". Для того, чтобы отключить отсечение пробелов, используйте атрибут trim со значением false.

    Следует иметь в виду, что отсечение пробелов работает только при вводе нового значения. Если в значении связанного атрибута уже присутствуют пробелы, они будут отображаться, пока пользователь не изменит значение поля.

  • Текстовое поле всегда вместо введенной пустой строки возвращает null. Соответственно, при включенном атрибуте trim строка, состоящая из одних пробелов также превратится в null.

  • Метод setCursorPosition() используется для установки позиции курсора в указанный индекс (начинается с 0). После вызова метода поле принимает фокус ввода.