ComboBox

ComboBox позволяет пользователям выбрать один элемент из выпадающего списка. Он поддерживает фильтрацию элементов на основе пользовательского ввода.

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

Основы

Используйте ComboBox, если:

  • Пользователям необходимо выбрать один вариант.

  • Список должен быть компактным. Это удобно, когда список опций слишком длинный для RadioButtonGroup или SingleSelectList.

  • Пользователям нужна функция фильтрации.

См. также EntityComboBox.

По умолчанию Jmix Studio генерирует ComboBox при создании экрана редактора сущностей с атрибутом перечисления. Например, сущность Customer имеет атрибут hobby типа Hobby, который представляет собой перечисление.

combo box

В следующем примере экран определяет контейнер данных customerDc для сущности Customer, имеющей атрибут hobby. В элементе comboBox атрибут dataContainer содержит ссылку на контейнер данных customerDc, а атрибут property ссылается на атрибут сущности hobby. В данном случае атрибут сущности является перечислением, и в выпадающем списке отображаются локализованные имена всех значений перечисления.

<data>
    <instance id="customerDc" class="ui.ex1.entity.Customer">
        <fetchPlan extends="_base"/>
    </instance>
</data>
<layout>
    <vbox spacing="true">
        <comboBox id="hobbyField"
                  dataContainer="customerDc"
                  property="hobby"
                  caption="msg://ui.ex1.entity/Customer.hobby"/>
    </vbox>
</layout>

Список опций

Список опций ComboBox можно задать с помощью методов setOptionsList(), setOptionsMap() и setOptionsEnum().

setOptionsList()

  • Метод setOptionsList() позволяет задать список опций компонента программно.

    Сначала объявите компонент в XML-дескрипторе:

    <comboBox id="maritalStatusField"
              dataContainer="customerDc"
              property="maritalStatus"
              caption="msg://ui.ex1.entity/Customer.maritalStatus"/>

    Затем инжектируйте компонент в контроллер и задайте список опций в методе onInit():

    @Autowired
    private ComboBox<String> maritalStatusField;
    
    @Subscribe
    public void onInit(InitEvent event) {
        List<String> list = new ArrayList<>();
        list.add("Married");
        list.add("Widowed");
        list.add("Separated");
        list.add("Divorced");
        list.add("Single");
        maritalStatusField.setOptionsList(list);
    }

    В выпадающем списке компонента будут отображены значения "Married", "Widowed", "Separated", "Divorced" и "Single". Выбранный статус будет помещен в атрибут maritalStatus сущности, расположенной в контейнере данных maritalStatus.

setOptionsMap()

  • Метод setOptionsMap() позволяет явно указать название строки для каждого значения опции.

    Сначала объявите компонент в XML-дескрипторе:

    <comboBox id="ratingField"
              dataContainer="orderDc"
              property="rating"
              caption="msg://ui.ex1.entity/Order.rating"/>

    Затем инжектируйте компонент в контроллер и задайте мэп опций в методе onInit():

    @Autowired
    private ComboBox<Integer> ratingField;
    
    @Subscribe
    public void onInit(InitEvent event) {
        Map<String, Integer> map = new LinkedHashMap<>();
        map.put("Poor", 2);
        map.put("Average", 3);
        map.put("Good", 4);
        map.put("Excellent", 5);
        ratingField.setOptionsMap(map);
    }

    В выпадающем списке компонента будут отображены строки "Poor", "Average", "Good", "Excellent". Однако значением компонента будет число, соответствующее выбранной строке. Оно будет помещено в атрибут rating сущности, находящейся в контейнере данных orderDc.

setOptionsEnum()

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

    Самый простой способ задать опции из класса перечисления – использовать атрибут optionsEnum в XML-дескрипторе:

    <comboBox id="hobbyComboBox"
              dataContainer="customerDc"
              property="hobby"
              optionsEnum="ui.ex1.entity.Hobby"
              caption="msg://ui.ex1.entity/Customer.hobby"/>

Пустая строка

nullName

Если у компонента ComboBox не установлен атрибут required, и если связанный атрибут сущности не объявлен как обязательный, то в списке опций компонента присутствует пустая строка, при выборе которой компонент возвращает значение null. Атрибут nullName позволяет задать строку, отображаемую в этом случае вместо пустой. Например:

<comboBox id="comboBox"
          dataContainer="customerDc"
          property="hobby"
          nullName="(not selected)"/>

В данном случае вместо пустой строки отобразится строка (not selected), при выборе которой в связанный атрибут сущности подставится значение null.

combo box null name

При программном задании списка опций методом setOptionsList() можно передать одну из опций в метод setNullSelectionCaption(). Тогда при ее выборе пользователем значением компонента будет null.

nullOptionVisible

XML-атрибут nullOptionVisible устанавливает видимость элемента со значением null в списке опций. Значение false позволяет сделать ComboBox необязательным, но без null опции. Значение по умолчанию – true.

Фильтрация опций

ComboBox поддерживает фильтрацию элементов. Атрибут filterMode задает тип фильтрации опций при вводе пользователя:

  • NO - ComboBox не использует фильтрацию.

  • STARTS_WITH - ComboBox показывает значения, заголовки которых начинаются с введенного текста.

  • CONTAINS - ComboBox показывает значения, заголовки которых содержат введенный текст (используется по умолчанию).

Используйте атрибут textInputAllowed для отключения фильтрации:

<comboBox id="comboBoxNoFilter"
          dataContainer="customerDc"
          property="hobby"
          textInputAllowed="false"/>

Это может быть удобно для коротких списков. Значение по умолчанию – true.

Пейджинг

ComboBox поддерживает механизм пейджинга, который помогает разбить длинный список элементов на несколько отдельных страниц. Количество страниц определяется размером страницы и количеством элементов в выпадающем списке.

Используйте атрибут pageLength, чтобы задать необходимое количество элементов на одной странице.

Если установить для pageLength значение 0, пейджинг будет отключен (т.е. все элементы видны).

Значение по умолчанию задано в свойстве jmix.ui.component.comboBoxPageLength.

Настройка ширины окна

Метод setPopupWidth() позволяет установить ширину выпадающего списка, которая передается в метод в виде строки. Используя относительное значение (например, "50%"), можно установить ширину выпадающего списка относительно ширины ComboBox. По умолчанию эта ширина имеет значение null, поэтому ширина выпадающего списка может быть больше ширины компонента, для того чтобы соответствовать содержимому всех отображаемых элементов. Если установить значение "100%", ширина выпадающего списка будет равна ширине ComboBox.

Валидация

Для проверки введенных в компонент ComboBox значений можно использовать валидатор во вложенном элементе validators.

Для ComboBox доступны следующие предопределенные валидаторы:

В приведенном ниже примере показано использование `NotEmptyValidator для hobbyValidField:

<comboBox id="hobbyValidField"
          dataContainer="customerDc"
          property="hobby"
          caption="msg://ui.ex1.entity/Customer.hobby">
    <validators>
        <notEmpty/>
    </validators>
</comboBox>

Обработка пользовательского ввода

Используйте метод setEnterPressHandler(), чтобы позволить пользователям вводить значение, которого нет в изначальном выпадающем списке, и сохранять его, чтобы выбрать элемент позже, не вводя снова:

@Subscribe
public void onInit(InitEvent event) {
    List<String> list = new ArrayList<>();
    list.add("Married");
    list.add("Widowed");
    list.add("Separated");
    list.add("Divorced");
    list.add("Single");
    maritalStatusField.setOptionsList(list);
    maritalStatusField.setEnterPressHandler(enterPressEvent -> {
        String text = enterPressEvent.getText();
        list.add(text);
        maritalStatusField.setOptionsList(list);
    });
}

setEnterPressHandler() вызывается, если пользователь ввел значение и нажал Enter. В данном случае новое значение добавляется в список опций и становится доступным для последующего использования.

События и слушатели

Чтобы сгенерировать заглушку слушателя в Jmix Studio, выберите компонент в XML-дескрипторе экрана или на панели иерархии Jmix UI и используйте вкладку Handlers на панели инспектора Jmix UI.

В качестве альтернативы вы можете воспользоваться кнопкой Generate Handler на верхней панели контроллера экрана.

ContextHelpIconClickHandler

EnterPressHandler

См. пример программной регистрации в разделе Обработка пользовательского ввода для ComboBox.

EnterPressHandler может быть предоставлен декларативно с помощью аннотации @Install в контроллере экрана. См. пример в разделе Обработка пользовательского ввода для EntityComboBox.

OptionsCaptionFilter

OptionsCaptionFilter используется для проверки того, соответствует ли элемент с заданной надписью заданной строке поиска.

В следующем примере введенная пользователем строка поиска проверяется на соответствие надписи элемента с учетом регистра.

@Install(to = "hobbyField", subject = "optionsCaptionFilter")
private boolean hobbyFieldOptionsCaptionFilter(ComboBox.OptionsCaptionFilteringContext
                                                       optionsCaptionFilteringContext) {
    return optionsCaptionFilteringContext.getItemCaption()
            .contains(optionsCaptionFilteringContext.getSearchString());
}

Чтобы задать предикат программно, используйте метод компонента setOptionsCaptionFilter().

OptionCaptionProvider

OptionIconProvider

Каждый элемент выпадающего списка может иметь значок слева. Чтобы установить значки, создайте реализацию интерфейса HasOptionIconProvider:

@Autowired
private ComboBox iconComboBox;

@Subscribe
public void onInit(InitEvent event) {
    Map<String, FontAwesome> iconMap = new HashMap<>();
    iconMap.put("Archive file", FontAwesome.FILE_ARCHIVE_O);
    iconMap.put("PDF file", FontAwesome.FILE_PDF_O);
    iconMap.put("TXT file", FontAwesome.FILE_TEXT_O);
    iconComboBox.setOptionsMap(iconMap);
}

@Install(to = "iconComboBox", subject = "optionIconProvider")
private String iconComboBoxOptionIconProvider(FontAwesome icon) {
    return "font-icon:" + icon;
}
combo box icons

Чтобы задать функцию, которая предоставляет значок для опций программно, используйте метод компонента setOptionIconProvider().

OptionImageProvider

Делегирующий метод OptionImageProvider позволяет задать изображения для опций, отображаемых компонентом ComboBox.

private Image imageResource;

@Subscribe
public void onInit(InitEvent event) {
    imageResource = uiComponents.create(Image.NAME);
}

@Install(to = "comboBoxWithImages", subject = "optionImageProvider")
private Resource comboBoxWithImagesOptionImageProvider(Hobby hobby) {
    return imageResource.setSource(ThemeResource.class).setPath("icons/check-mark.png");
}

Этот делегат возвращает один из типов ресурсов.

combo box option image provider

Чтобы создать его программно, используйте метод компонента setOptionImageProvider().

OptionStyleProvider

Validator

Добавляет экземпляр валидатора в компонент. validator должен выбросить ValidationException, если значение недопустимо.

Если вас не устраивают предопределенные валидаторы, добавьте свой собственный экземпляр валидатора:

@Install(to = "iconComboBox", subject = "validator")
protected void iconComboBoxValidator(FontAwesome icon) {
    if (icon != null)
        if (icon == FontAwesome.FILE_PDF_O)
            throw new ValidationException("The file type you selected " +
                    "is not currently supported");
}

ValueChangeEvent

XML-атрибуты ComboBox

Просматривать и редактировать атрибуты, применимые к компоненту, можно с помощью панели инспектора Jmix UI в конструкторе экранов Studio.

XML-элемент ComboBox