ComboBox 下拉列表

ComboBox - 下拉列表 支持用户从下拉列表中选择单一值。支持基于用户的输入对选项进行过滤的功能。

组件的 XML 名称:comboBox

基本用法

满足下列情况可以使用 ComboBox

  • 用户需要选择单一选项。

  • 选项列表应该比较紧凑。如果选项列表对于 RadioButtonGroupSingleSelectList 太长时,用下拉列表更方便。

  • 用户需要过滤功能。

也可以参阅 EntityComboBox 实体下拉框

Jmix Studio 在创建实体编辑器时,会给实体的枚举属性生成 ComboBox 组件。例如,Customer 实体有 hobby 属性,这是一个 Hobby 枚举类型的属性。

combo box

在下面的例子中,界面为 Customer 实体定义了 customerDc 数据容器,该实体有 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"。选择的值会设置到 customerDc 数据容器中的 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" 字符串。但是组件的值是选中字符串对应的数字。选择的值会设置到 orderDc 数据容器中的 rating 属性上。

setOptionsEnum()

  • setOptionsEnum() 方法使用枚举类作为参数。下拉列表中展示枚举值的本地化名称,而组件值为枚举值。

    使用枚举类设置选项最简便的方式是使用 XML 描述中的 optionsEnum 属性:

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

Null 选项

nullName

如果 ComboBox 下拉框组件非必需,并且对应的实体属性也非必需,下拉选项会包含一个空行。如果选择了空行,组件值为 null。 使用 nullName 属性设置在“空行”上显示的文本。以下为一个示例:

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

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

combo box null name

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

nullOptionVisible

nullOptionVisible XML 属性设置是否在下拉列表显示空值。设置为 false,令 ComboBox 为非必需,但是不提供空值选项。该属性默认为 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 元素中使用 validator

ComboBox 可使用下列预定义的验证器:

下面的例子中,我们展示为 hobbyValidField 使用 NotEmptyValidator

<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() 会在用户输入值并按下回车时调用。然后会在选项列表加入输入的新值,之后都能使用。

事件和处理器

如需使用 Jmix Studio 生成处理器的桩代码,需要在界面 XML 描述或者 Jmix UI 层级结构面板选中该组件,然后用 Jmix UI 组件面板的 Handlers 标签页生成。

或者可以使用界面控制器顶部面板的 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

如需编程式的设置图标的 provider,可以用组件的 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");
}

代理返回一种 resource 类型

combo box option image provider

如需编程式注册选项图片 provider,可以用组件的 setOptionImageProvider() 方法。

OptionStyleProvider

Validator

为组件添加 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

参阅 ValueChangeEvent

ComboBox XML 元素