3.5.2.1.31. PickerField

PickerField позволяет отображать экземпляр сущности в текстовом поле и выполнять действия нажатием на кнопки справа.

PickerField

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

  • Как правило, PickerField используется для работы со ссылочными атрибутами сущностей. При этом компоненту достаточно указать атрибуты dataContainer и property:

    <data>
        <instance id="carDc" class="com.haulmont.sample.core.entity.Car" view="carEdit">
            <loader/>
        </instance>
    </data>
    <layout>
        <pickerField dataContainer="carDc" property="color"/>
    </layout>

    Как видно из примера, в экране описывается контейнер данных carDc для некоторой сущности Car, имеющей атрибут color. В элементе pickerField в атрибуте dataContainer указывается ссылка на контейнер, а в атрибуте property − название атрибута сущности, значение которого должно быть отображено в компоненте. Атрибут сущности должен являться ссылкой на другую сущность, в приведенном примере это Color.

  • Для PickerField можно определить произвольное количество действий, отображаемых кнопками справа.

    Это можно сделать как в XML-дескрипторе с помощью вложенного элемента actions, так и программно в контроллере методом addAction().

    • Существует набор стандартных действий для PickerField: picker_lookup, picker_clear, picker_open. Они выполняют соответственно выбор связанной сущности, очистку поля и открытие экрана редактирования выбранной связанной сущности. Для стандартных действий в XML нужно определить идентификатор действия и его тип с помощью атрибута type.

      Если при объявлении компонента никаких действий в элементе actions не задано, загрузчик XML определит для него действия lookup и clear. Чтобы добавить к действиям по умолчанию, например, действие open, нужно определить элемент actions следующим образом:

      <pickerField dataContainer="carDc" property="color">
          <actions>
              <action id="lookup" type="picker_lookup"/>
              <action id="open" type="picker_open"/>
              <action id="clear" type="picker_clear"/>
          </actions>
      </pickerField>

      Элемент action не дополняет, а переопределяет набор стандартных действий, поэтому необходимо указывать идентификаторы всех требуемых действий. Компонент примет следующий вид:

      gui pickerFieldActionsSt

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

      @Inject
      protected PickerField<Color> colorField;
      
      @Subscribe
      protected void onInit(InitEvent event) {
          colorField.addAction(actions.create(OpenAction.class));
      }

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

      @Inject
      private InstanceContainer<Car> carDc;
      @Inject
      private UiComponents uiComponents;
      @Inject
      private Actions actions;
      
      @Subscribe
      protected void onInit(InitEvent event) {
          PickerField<Color> colorField = uiComponents.create(PickerField.NAME);
          colorField.setValueSource(new ContainerValueSource<>(carDc, "color"));
          colorField.addAction(actions.create(LookupAction.class));
          colorField.addAction(actions.create(OpenAction.class));
          colorField.addAction(actions.create(ClearAction.class));
          getWindow().add(colorField);
      }

      Поведение стандартных действий можно кастомизировать, если подписаться на событие ActionPerformedEvent и предоставить собственную реализацию действия. Например, так можно задать специфический экран выбора:

      @Inject
      private ScreenBuilders screenBuilders;
      @Inject
      private PickerField<Color> pickerField;
      
      @Subscribe("pickerField.lookup")
      protected void onPickerFieldLookupActionPerformed(Action.ActionPerformedEvent event) {
              screenBuilders.lookup(pickerField)
                       .withScreenClass(CustomColorBrowser.class)
                       .build()
                       .show();
      }

      Подробнее см. раздел Открытие экранов

    • Произвольные действия в XML-дескрипторе также определяются во вложенном элементе actions, а логика действий описывается в соответствующем событии, например:

      <pickerField dataContainer="orderDc" property="customer">
          <actions>
              <action id="lookup"/>
              <action id="show" icon="PICKERFIELD_OPEN" caption="Show"/>
          </actions>
      </pickerField>
      @Inject
      private PickerField<Customer> pickerField;
      
      @Subscribe("pickerField.show")
      protected void onPickerFieldShowActionPerformed(Action.ActionPerformedEvent event) {
          CustomerEdit customerEdit = screenBuilders.editor(pickerField)
                  .withScreenClass(CustomerEdit.class)
                  .build();
          customerEdit.setDiscount(true);
          customerEdit.show();
      }

      Декларативное и программное создание действий подробно описано в разделе Действия. Интерфейс Action.

  • Компонент PickerField можно использовать без непосредственной привязки к данным, то есть без указания dataContainer и property. В этом случае для указания типа сущности, с которой должен работать PickerField, используется атрибут metaClass. Например:

    <pickerField id="colorField" metaClass="sample_Color"/>

    Экземпляр выбранной сущности можно получить, инжектировав компонент в контроллер и вызвав его метод getValue().

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

  • В компоненте PickerField можно использовать горячие клавиши: см. Горячие клавиши.

  • Компонент PickerField может иметь значок слева. Ниже приведен пример использования функции в методе setOptionIconProvider() контроллера экрана. Значок "cancel" должен быть установлен, когда значение поля равно null; в противном случае должен быть установлен значок "chain".

    @Inject
    private PickerField<Customer> pickerField;
    
    protected String generateIcon(Customer customer) {
        return (customer!= null) ? "icons/chain.png" : "icons/cancel.png";
    }
    
    @Subscribe
    private void onInit(InitEvent event) {
        pickerField.setOptionIconProvider(this::generateIcon);
    }
    gui pickerField icons