3.5.2.1.25. 下拉框

该控件支持从下拉列表中选择值。下拉列表提供基于用户的输入对数据进行过滤的功能,也支持分页显示数据。

gui lookupField

该组件的 XML 名称是: lookupField

  • 使用 LookupField 下拉框最简单的例子是从实体属性中选择枚举值。比如,Role 角色实体中有 type 属性,为枚举类型。用户可以通过 LookupField 下拉框控件编辑该属性:

    <data>
        <instance id="roleDc"
                  class="com.haulmont.cuba.security.entity.Role"
                  view="_local">
            <loader/>
        </instance>
    </data>
    <layout expand="editActions" spacing="true">
        <lookupField dataContainer="roleDc" property="type"/>
    </layout>

    在上面的例子中,使用 roleDc 数据容器选择 Role 实体数据。lookupField 下拉框组件中,数据容器的连接通过 dataContainer 属性定义,实体属性的名称定义在 property 属性中。此时,这个属性为枚举类型,控件的下拉列表中会显示所有枚举值的本地化名称

  • 类似的,LookupField 下拉框也可以用来选择实体实例。选项容器属性可以用来创建一系列选项:

    <data>
        <instance id="carDc" class="com.haulmont.sample.core.entity.Car" view="carEdit">
            <loader/>
        </instance>
        <collection id="colorsDc" class="com.haulmont.sample.core.entity.Color" view="_minimal">
            <loader id="colorsDl">
                <query>
                    <![CDATA[select e from sample$Color e]]>
                </query>
            </loader>
        </collection>
    </data>
    <layout>
        <lookupField dataContainer="carDc" property="color" optionsContainer="colorsDc"/>
    </layout>

    这种时候,colorsDc 数据容器中的 Color 实体的实例名称会显示在下拉列表中,被选择的值会被设置到 carDc 数据容器中 Car 实体的 color 属性中。

    captionProperty定义显示到下拉框的实体属性值,而非实例名称,这样可以设置下拉列表的文字值。

  • 使用 setOptionCaptionProvider() 方法可以为 LookupField 组件显示的字符串选项名定义标题:

    lookupField.setOptionCaptionProvider((item) -> item.getLocalizedName());
  • 选项列表还可以通过 setOptionsList()setOptionsMap()setOptionsEnum() 设置,也可以在 XML 描述中通过 optionsContainer 或者 optionsDatasource 属性设置。

    • setOptionsList() - 通过代码指定选项列表。首先在 XML 描述中声明组件:

      <lookupField id="numberOfSeatsField" dataContainer="modelDc" property="numberOfSeats"/>

      然后将组件注入界面控制器,在 onInit() 方法中设置选项列表:

      @Inject
      protected LookupField<Integer> numberOfSeatsField;
      
      @Subscribe
      public void onInit(InitEvent event) {
          List<Integer> list = new ArrayList<>();
          list.add(2);
          list.add(4);
          list.add(5);
          list.add(7);
          numberOfSeatsField.setOptionsList(list);
      }

      组件的下拉列表中会显示 2, 4, 5 和 7。被选择的值会设置到 modelDc 数据容器中的 numberOfSeats 属性上。

    • setOptionsMap() 可以提供选项 map。比如为 XML 描述中声明的 numberOfSeatsField 组件指定选项 map(在 onInit() 方法中):

      @Inject
      protected LookupField<Integer> numberOfSeatsField;
      
      @Subscribe
      public void onInit(InitEvent event) {
          Map<String, Integer> map = new LinkedHashMap<>();
          map.put("two", 2);
          map.put("four", 4);
          map.put("five", 5);
          map.put("seven", 7);
          numberOfSeatsField.setOptionsMap(map);
      }

      组件下拉框会显示 twofourfiveseven 文本。但是组件的值则是与文本对应的数字值。数字值会被设置到 modelDc 数据容器中的 numberOfSeats 属性上。

    • setOptionsEnum() 需要枚举类做为参数。下拉列表会显示枚举值的本地化名称,组件的值则为枚举值。

  • setPopupWidth() 可以设置下拉列表的宽度,宽度用字符串格式传递给该方法。使用相对单位(比如,"50%")可以设置下拉列表的宽度是针对于 LookupField 本身的相对值。默认情况下,该宽度设置为 null,下拉列表的宽度为了适应显示内容的宽度而可以大于组件的宽度。通过设置该值为 "100%",可以使得下拉列表的宽度等于 LookupField 的宽度。

  • 通过 setOptionStyleProvider() 可以为组件显示的不同的选项设置分别的 style name:

    lookupField.setOptionStyleProvider(entity -> {
        User user = (User) entity;
        switch (user.getGroup().getName()) {
            case "Company":
                return "company";
            case "Premium":
                return "premium";
            default:
                return "company";
        }
    });
  • 下拉列表中的组件可以在左边设置对应的图标。在界面控制器中使用 setOptionIconProvider() 方法设置:

    lookupField.setOptionIconProvider(entity -> {
        if (entity.getType() == LegalStatus.LEGAL)
            return "icons/icon-office.png";
        return "icons/icon-user.png";
    });
    gui lookupField 2

    如果使用 SVG 图标, 显式设置图标大小以避免图标覆盖。

    <svg version="1.1"
         id="Capa_1"
         xmlns="http://www.w3.org/2000/svg"
         xmlns:xlink="http://www.w3.org/1999/xlink"
         xml:space="preserve"
    
         style="enable-background:new 0 0 55 55;"
         viewBox="0 0 55 55"
    
         height="25px"
         width="25px">
  • setOptionImageProvider() 方法可以定义 LookupField 组件显示的选项图片。该方法设置一个接收资源类型参数的函数。

    @Inject
    private LookupField<Customer> lookupField;
    @Inject
    private Image imageResource;
    
    @Subscribe
    private void onInit(InitEvent event) {
       lookupField.setOptionImageProvider(e ->
          imageResource.createResource(ThemeResource.class).setPath("icons/radio.svg"));
    }
  • 如果 LookupField 下拉框组件非required,并且对应的实体属性也非必须,下拉选项会包含一个空行。如果选择了空行,组件值为 null. 使用 nullName 属性设置在“空行”上显示的文本。以下为一个示例:

    <lookupField dataContainer="carDc" property="colour" optionsContainer="colorsDs" nullName="(none)"/>

    这样,下拉框中的“空行”上会显示 (none) 文本。如果用户选择了该行,对应的实体属性值会设置为 null

    如果在代码中通过 setOptionsList() 设置了选项, 可以用 setNullOption() 方法设置空行文本,这样,如果用户选择了该行,组件值则为 null

    LookupField 过滤器:
    • filterMode 属性设置基于用户输入的过滤模式:

      • NO − 不过滤。

      • STARTS_WITH − 选项文本以用户输入开头。

      • CONTAINS − 选项文本包含用户输入(默认模式)。

    • setFilterPredicate() 方法用来设置过滤方法,该方法判断元素是否跟查找文字匹配。比如:

      BiFunction<String, String, Boolean> predicate = String::contains;
      lookupField.setFilterPredicate((itemCaption, searchString) ->
              predicate.apply(itemCaption.toLowerCase(), searchString));

      FilterPredicatetest 方法可以用来客户化过滤逻辑,比如处理方言/特殊字符:

      lookupField.setFilterPredicate((itemCaption, searchString) ->
              StringUtils.replaceChars(itemCaption, "ÉÈËÏÎ", "EEEII")
                  .toLowerCase()
                  .contains(searchString));
  • LookupField 组件在没有合适选项的时候可以处理用户的输入,通过 setNewOptionHandler() 来处理,示例:

    @Inject
    private Metadata metadata;
    @Inject
    private LookupField<Color> colorField;
    @Inject
    private CollectionContainer<Color> colorsDc;
    
    @Subscribe
    protected void onInit(InitEvent event) {
        colorField.setNewOptionHandler(caption -> {
            Color color = metadata.create(Color.class);
            color.setName(caption);
            colorsDc.getMutableItems()
                    .add(color);
            colorField.setValue(color);
        });
    }

    当用户输入不匹配任何选项的值并且按下回车键时,会触发调用新选项处理器。这时,上述代码会创建一个新的 Color 实例,name 属性值为用户输入,并且这个实例会加到下拉选项数据容器中,做为该控件当前被选中值。

    除了使用 setNewOptionHandler() 方法来处理用户输入,还可以在 XML 描述中通过 newOptionHandler 属性来指定控制器处理的方法。这个方法需要两个参数,一个是 LookupField 类型,指向组件实例,另一个是 String 类型,指向用户输入。newOptionAllowed 属性也可以用来开启是否允许输入新值。

  • nullOptionVisible XML 属性设置是否在下拉列表显示空值。可以配置 LookupField 下拉框非 required但是不提供空值选项。

  • textInputAllowed 属性可以禁止过滤器功能及键盘输入。对短列表来说很方便。默认值为 true

  • pageLength 属性重新设置下拉列表中一页选项的个数,默认值在cuba.gui.lookupFieldPageLength应用程序属性中定义。

  • 在基于 Halo 主题的 Web 客户端,可以自定义样式,通过 XML stylename 属性或在界面控制器中通过代码设置:

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

    通过代码设置时,从 HaloTheme 类中选择 LOOKUPFIELD_ 开头的常量样式:

    lookupField.setStyleName(HaloTheme.LOOKUPFIELD_BORDERLESS);

    LookupField 下拉框样式有:

    • align-center - 文本居中对齐。

    • align-right - 文本靠右对齐。

    • borderless - 文本不要边框和背景。