Table

Table - 表格 组件以表格的方式展示信息、对数据进行排序、管理表格列和表头,并对选中的行执行操作。

组件的 XML 名称:table

基本用法

典型的表格如下所示:

table anatomy
  1. 表头

  2. 数据行

  3. 列控制按钮

  4. 分页器

  5. 排序按钮

  6. 按钮面板

在界面 XML 描述中定义表格组件的示例:

<data>
    <collection id="customersDc" class="ui.ex1.entity.Customer">
        <fetchPlan extends="_base"/>
        <loader id="customersDl">
            <query>
                <![CDATA[select e from uiex1_Customer e]]>
            </query>
        </loader>
    </collection>
</data>
<layout>
    <table id="customersTable"
           width="100%"
           dataContainer="customersDc">
        <actions>
            <action id="create" type="create"/>
            <action id="edit" type="edit"/>
            <action id="remove" type="remove"/>
            <action id="sendByEmail" type="sendByEmail">
                <properties>
                    <property name="recipientAddress" value="peter@example.com"/>
                </properties>
            </action>
        </actions>
        <columns>
            <column id="level"/>
            <column id="age"/>
            <column id="hobby"/>
            <column id="firstName"/>
            <column id="lastName"/>
            <column id="rewardPoints"/>
        </columns>
        <simplePagination/>
        <buttonsPanel id="buttonsPanel" alwaysVisible="true">
            <button id="createBtn" action="customersTable.create"/>
            <button id="editBtn" action="customersTable.edit"/>
            <button id="removeBtn" action="customersTable.remove"/>
            <button id="sendBtn" action="customersTable.sendByEmail"/>
        </buttonsPanel>
    </table>
</layout>

在上面的示例中,为 Customer 实体使用了 集合数据容器Table 组件通过 dataContainer 属性与数据容器绑定,columns 元素定义那些实体属性要显示在数据网格的列中。

数据绑定

声明式绑定

通常,使用 dataContainer 属性在界面 XML 描述中将数据与 table 绑定。此时需要使用一个 集合数据容器

使用键值对容器

表格还可以绑定至 键值对容器 展示查询的纯数值和聚合值。示例:

<data>
    <keyValueCollection id="salesDc">
        <loader id="salesLoader">
            <query>
                <![CDATA[select o.customer, o.customer.firstName,
                sum(o.amount) from uiex1_Order o group by o.customer]]>
            </query>
        </loader>
        <properties>
            <property class="ui.ex1.entity.Customer" name="customerEntity"/>
            <property datatype="string" name="customerName"/>
            <property datatype="decimal" name="sum"/>
        </properties>
    </keyValueCollection>
</data>
<layout>
    <table id="keyValueTable" width="100%" dataContainer="salesDc">
        <columns>
            <column id="customerName" caption="Customer"/>
            <column id="sum" caption="Summary amount" align="RIGHT"/>
        </columns>
    </table>
</layout>

编程式绑定

如需以编程的方式在界面控制器定义数据容器,则可以在 XML 中设置 metaClass 属性而非 dataContainer

<table id="customersTable1" width="100%" metaClass="uiex1_Customer">
    <columns>
        <column id="firstName"/>
        <column id="lastName"/>
    </columns>
</table>

界面控制器中,使用 ContainerTableItems 类将表格和数据容器绑定:

customersTable1.setItems(new ContainerTableItems<>(customersDc));

columns 元素

表格的列集合定义在 columns 元素中。如果未指定,则通过 dataContainer 定义的 fetch plan 自动确定。

columns 元素有如下属性:

  • includeAll 加载 dataContainer 中定义的 fetchPlan 的所有属性。

    在下面的例子中,我们显示了 customersDc 中使用 fetch plan 的所有属性:

    <table id="customersTableIncludeAll"
           width="100%"
           dataContainer="customersDc">
        <columns includeAll="true"/>
    </table>

    如果实体的 fetch plan 包含引用属性,该属性会按照其 实例名 进行展示。如果需要展示一个特定的级联属性,则需要在 fetch plan 和 column 元素中定义:

    <data>
        <collection id="customersDc1" class="ui.ex1.entity.Customer">
            <fetchPlan extends="_base">
                <property name="city" fetchPlan="_base">
                    <property name="country" fetchPlan="_base"/>
                </property>
            </fetchPlan>
            <loader id="customersDl1">
                <query>
                    <![CDATA[select e from uiex1_Customer e]]>
                </query>
            </loader>
        </collection>
    </data>
    <layout>
        <table id="tableIncludeAllReference"
               width="100%"
               dataContainer="customersDc1">
            <columns includeAll="true">
                <column id="city.country.name"/>
            </columns>
        </table>
    </layout>
  • exclude exclude 英文逗号分隔的属性列表,这些属性不会被加载到表格。

    在下面的例子中,我们会显示除了 idmaritalStatusemail 之外的所有属性:

    <table id="tableExclude"
           width="100%"
           dataContainer="customersDc1">
        <columns includeAll="true"
                 exclude="id,maritalStatus,email"/>
    </table>

column 元素

每一列是在内部的 column 元素中描述。

id 是一个必需属性,指定展示在列中实体属性的名称。可以是数据容器中实体的一个属性或者一个关联实体(用 . 访问对象关系图)。示例:

<columns>
    <column id="firstName"/>
    <column id="lastName"/>
    <column id="city.name"/>
    <column id="city.country.name"/>
</columns>

列对齐

支持三种类型的列对齐方式:LEFT(默认)、CENTERRIGHT

通常数字采用右对齐,而其他内容采用左对齐。示例:

<table id="keyValueTable" width="100%" dataContainer="salesDc">
    <columns>
        <column id="customerName" caption="Customer"/>
        <column id="sum" caption="Summary amount" align="RIGHT"/>
    </columns>
</table>
table column align

列标题

caption - 可选属性,定义列标题。如果未设置,会使用实体属性的 本地化名称

captionAsHtml - 可选属性,定义是否可以在列标题中使用 HTML 标签。默认为 false

<column id="firstName"
        captionAsHtml="true"
        caption="msg://firstName"/> (1)
<column id="lastName"/> (2)
1 列标题含有 HTML 标签:
ui.ex1.screen.component.table/firstName=<em>First Name</em>
2 默认标题列
table captions

列可见性

collapsed - 可选属性,设置为 true 时自动隐藏该列。collapsed 属性默认值为 false。用户可以通过表格右上角的 table column control button 按钮提供的菜单控制列的可见性,此时需要设置 columnControlVisibletrue

visible 属性设置列的可见性。可选值:truefalse。默认所有列都可见。

下面示例中,我们看看 collapsedvisible 属性的不同之处:

<columns>
    <column id="firstName"
            collapsed="true"/>
    <column id="lastName"
            visible="false"/>
    <column id="city"/>
</columns>
table columns visibility

可以看到,firstName 列默认是折叠不显示的,但是用户可以通过 table column control button 按钮的下拉菜单显示它。

同时,lastName 是无法通过用户操作看见的。

列宽度

width - 可选属性,定义列宽。只支持以像素为单位的数值类型。

<columns>
    <column id="firstName" width="100"/>
    <column id="lastName" width="150"/>
    <column id="city" width="100"/>
</columns>
table column width

expandRatio - 可选属性,设置列宽占比。比值必须大于等于 0。如果至少有一列设置了其他值,则忽略所有的隐式值,并且只使用设置的值。如果同时设置了 widthexpandRatio 属性,会导致应用程序错误。

<columns>
    <column id="firstName" expandRatio="1"/>
    <column id="lastName" expandRatio="1.5"/>
    <column id="city" expandRatio="1"/>
</columns>
table column expand ratio

用户可以调整列宽:

table columns resize

只有当整个表的 enable 属性设置为 false 时,列才维持固定宽度。

列重排

Table 提供拖拽功能,用户可以改变表格内列的展示顺序。

table columns reordering

列重排的功能是默认开启的。如需禁用,可设置 reorderingAllowed 属性为 false

<column id="firstName"
        link="true"
        linkScreenOpenMode="DIALOG"/>
<column id="lastName"/>
<column id="city"/>
table columns link

Maximum Text Length

maxTextLength - 可选属性,允许限制单元格中的字符数。多余字符用省略号代替。用户可以点击可见部分来查看完整的文本。

如果实际值和最大允许字符数之间的差异不超过 10 个字符,则多余字符仍然显示。

下面例子中,有些单元格的值长度大于 maxTextLength+10,则省略。

<columns>
    <column id="firstName"/>
    <column id="lastName"/>
    <column id="email" maxTextLength="15"/>
    <column id="city"/>
</columns>
table max text length

文本格式化

column 元素可以包含一个内部的 formatter 元素,支持以不同于 Datatype 标准的格式显示属性值:

<table id="tableColumnFormatter"
       width="100%"
       dataContainer="ordersDc">
    <columns>
        <column id="customer"/>
        <column id="amount"/>
        <column id="deliveryTime">
            <formatter>
                <date format="h:mm a"/>
            </formatter>
        </column>
    </columns>
</table>

标题属性

captionProperty 属性指定一个要显示在列中的实体属性名称,而不是显示 id 指定的实体属性值。例如,如果有一个包含 nameid 属性的实体 City,则可以定义以下列:

<column id="city"
        caption="City ID"
        captionProperty="id"/>

此时,列中将会显示 City 实体的 id 属性,但是列的排序是根据 City 实体的 name 属性。

table captions

Multi-Line Cells

multiLineCells 设置为 true 可以让包含多行文本的单元格显示多行。在这种模式下,浏览器会一次加载表格中当前页的所有行,而不是延迟加载表格的可见部分。这样会使得数据带滚动条并可能影响性能。默认值为 false

table multi line cell

选择

Table 组件支持对数据行进行单选和多选。

单选模式

在单选模式中,用户一次只能选择单一的数据行。这是表格默认的选择模式。

多选模式

multiselect 属性可以为表格行设置多选模式。如果 multiselecttrue,用户可以按住 CtrlShift 键在表格中选择多行。默认情况下关闭多选模式。

Show Selection

如果 showSelection 属性设置为 false,则不高亮显示当前行。

Text Selection

textSelectionEnabled 属性定义是否可以在单元格中选取文本。默认值 false

空状态

在数据容器没有数据或者没有设置数据容器时,支持为 Table 设置展示空状态消息或链接。

空状态消息通过 emptyStateMessage 属性定义。可以用于显示无数据的原因。

示例:

<table id="tablePlaceholder"
       width="100%"
       height="200"
       metaClass="uiex1_Customer"
       emptyStateMessage="No customers added."
       emptyStateLinkMessage="Add customer">
    <columns>
        <column id="firstName"/>
        <column id="lastName"/>
    </columns>
</table>
table placeholder

生成 emptyStateLinkClickHandler 处理空状态链接的点击:

@Install(to = "tablePlaceholder", subject = "emptyStateLinkClickHandler")
private void tablePlaceholderEmptyStateLinkClickHandler(
        Table.EmptyStateClickEvent<Customer> emptyStateClickEvent) {
    screenBuilders.editor(emptyStateClickEvent.getSource())
            .newEntity()
            .show();
}

如需以编程的方式注册点击处理器,使用组件的 setEmptyStateLinkClickHandler() 方法。

emptyStateMessageemptyStateLinkMessage 属性都可以从 消息包 中加载本地化消息。

表头可见性

columnHeaderVisible 设置表格的表头是否展示。默认展示。

列可见控制

用户可以用表格 header 右侧的 table column control button 列控制按钮选择显示哪些列。

当前展示列在下拉列表中是勾选状态。其他的菜单项:

  • Select all - 展示所有列。

  • Deselect all - 隐藏除了第一列之外所有能隐藏的列。第一列必须显示,以保证表格功能正常。

table column control using

如果 columnControlVisible 属性设置为 false,则用户不能隐藏列。

聚合

Table 支持对行内值进行聚合运算。

支持下列运算符:

  • SUM - 求和

  • AVG - 求平均值

  • COUNT - 计数

  • MIN - 最小值

  • MAX - 最大值

如需启用对表格的行进行聚合运算,按照下列配置:

  1. 设置 aggregatable 属性值为 true

  2. 为表格的聚合列设置 aggregation 元素。

  3. 设置 aggregation 元素的 type 属性,表示聚合的函数。

聚合值展示在附加行中。

aggregationStyle 属性可以设置聚合值行的位置:TOPBOTTOM。默认为 TOP

默认情况下,聚合列只支持数字类型,比如 IntegerDoubleLongBigDecimal

带聚合列的 Table XML 描述示例:

<table id="tableAggregation"
       width="100%"
       aggregatable="true"
       dataContainer="customersDc1">
    <columns>
        <column id="firstName"/>
        <column id="lastName"/>
        <column id="rewardPoints"/>
        <column id="age">
            <aggregation type="AVG"/>
        </column>
    </columns>
</table>
table aggregation

valueDescription 属性定义一个提示,当用户的光标悬停在聚合值上时通过弹出框展示这个提示。对于上面列出的运算(SUMAVGCOUNTMINMAX),提示弹窗已经默认开启。

aggregation 元素支持 editable 属性。设置该属性为 true,且配合使用 AggregationDistributionProvider 可以支持开发者实现在各行之间分配数据。

可以指定不同于 Datatype 标准格式的 formatter 显示聚合值:

<column id="amount">
    <aggregation type="SUM">
        <formatter>
            <number format="#,##0.00"/>
        </formatter>
    </aggregation>
</column>

aggregation 元素还可以包含 strategyClass 属性,指定一个实现 AggregationStrategy 接口的类。

public class TableCustomerHobbyAggregation implements AggregationStrategy<Hobby, String> {
    @Override
    public String aggregate(Collection<Hobby> propertyValues) {
        Hobby mostFrequent = null;
        long max = 0;
        if (CollectionUtils.isNotEmpty(propertyValues)) {
            for (Hobby hobby : Hobby.values()) {
                long current = propertyValues.stream()
                        .filter(customerHobby -> customerHobby.equals(hobby))
                        .count();

                if (current > max) {
                    mostFrequent = hobby;
                    max = current;
                }
            }
        }

        if (mostFrequent != null) {
            return String.format("%s: %d/%d", mostFrequent.name(), max, propertyValues.size());
        }

        return null;
    }

    @Override
    public Class<String> getResultClass() {
        return String.class;
    }
}
<table id="tableAggregationStrategy"
       width="100%"
       aggregatable="true"
       dataContainer="customersDc">
    <columns>
        <column id="firstName"/>
        <column id="lastName"/>
        <column id="hobby">
            <aggregation
                    strategyClass="ui.ex1.screen.component.table.TableCustomerHobbyAggregation"/>
        </column>
    </columns>
</table>

排序

Table 支持对列数据进行排序。排序功能默认开启。

sortable 属性可以启用表格的排序功能。默认为 true。开启后,点击列名会在列名右边显示 table sortable down/table sortable up 图标。

使用特定 sortable 属性可以禁用该列的排序功能。

下面的例子中,我们禁用了 lastName 列的排序:

<columns>
    <column id="firstName"/>
    <column id="lastName" sortable="false"/>
    <column id="city"/>
</columns>

column 元素的 sort 属性可以设置该列的初始排序。值选项:

  • ASCENDING - 顺序(0 → 9 → A → Z)。

  • DESCENDING - 倒序(Z → A → 9 → 0)。

示例:

<columns>
    <column id="firstName" sort="DESCENDING"/>
    <column id="lastName"/>
    <column id="city"/>
</columns>

Table 一次只能按照一列进行排序。如果有多列设置了 sort 属性或者同时设置了 sortsortable="false",界面会报错。

分页

table 可以使用 SimplePagination 组件来提供分页功能:

<table id="tablePaging"
       width="100%"
       dataContainer="customersDc">
    <columns>
        <column id="firstName"/>
        <column id="lastName"/>
        <column id="hobby"/>
        <column id="age"/>
    </columns>
    <simplePagination
            itemsPerPageVisible="true"
            itemsPerPageOptions="2, 4, 6"/>
</table>
table pagination

或者,可以使用独立的 Pagination 组件。

Table 操作

Table 组件实现了 ActionsHolder 接口,可以包含自定义操作和 标准列表操作

表格的操作定义在内部的 actions 元素中。

如果操作有标题,则会显示在表格的 右键菜单 中。此外,表格的操作可以分配给界面中任意位置的按钮。

可以用 ButtonsPanel 容器在表格上方显示操作按钮。

<table id="tableWithActions"
       width="100%"
       dataContainer="customersDc">
    <actions>
        <action id="create" type="create"/> (1)
        <action id="edit" type="edit"/>
        <action id="remove" type="remove"/>
        <action id="about" caption="Get info"/> (2)
    </actions>
    <columns>
        <column id="age"/>
        <column id="firstName"/>
        <column id="lastName"/>
    </columns>
    <buttonsPanel id="buttonsActionsPanel" alwaysVisible="true"> (3)
        <button id="create" action="tableWithActions.create"/>
        <button id="edit" action="tableWithActions.edit"/>
        <button id="remove" action="tableWithActions.remove"/>
        <button id="about" action="tableWithActions.about"/>
    </buttonsPanel>
</table>
1 定义 create 标准操作。
2 定义 about 自定义操作。
3 在表格内定义 ButtonsPanel 容器。
table actions

列生成

通过 columnGenerator 处理器可以提供自定义的列数据展示。

在渲染表格时,事件处理器由框架对每个单元格进行调用。处理器接收对应渲染行的实体实例作为参数,返回在单元格中需要展示的可视化组件。

可以用 Studio 为表格列创建 columnGenerator 处理器(参阅 处理器),并实现如下:

@Install(to = "tableGeneratedColumn.hasEmail", subject = "columnGenerator")
private Component tableGeneratedColumnIsEmailColumnGenerator(Customer customer) {
    CheckBox hasEmail = uiComponents.create(CheckBox.class);
    hasEmail.setValue(customer.getEmail() != null);
    return hasEmail;
}

如只需展示动态文本,可以用特殊的 Table.PlainTextCell 类而不是 Label 组件。这样渲染更快,表格性能也更好。

@Install(to = "tableGeneratedColumn.fullName", subject = "columnGenerator")
private Component tableGeneratedColumnFullNameColumnGenerator(Customer customer) {
    return new Table.PlainTextCell(customer.getFirstName() + " " + customer.getLastName());
}
<table id="tableGeneratedColumn"
       width="100%"
       dataContainer="customersDc">
    <columns>
        <column id="age"/>
        <column id="firstName"/>
        <column id="lastName"/>
        <column id="fullName" caption="Full name"/>
        <column id="email"/>
        <column id="hasEmail" caption="Has email"/>
    </columns>
</table>

fullNameisEmail 是生成列。

table generated columns

当列的 id 指定关联实体的属性时(即,包含 “.”),columnGeneration 处理器需要按照下面示例中的方法定义。

  • 关联实体属性列:

    <column id="city.country.name"/>
  • 对应的 columnGenerator 处理器:

    @Install(to = "countryTable.[city.country.name]", subject = "columnGenerator")
    private Component countryTableCityCountryNameColumnGenerator(Customer customer) {
        return new Table.PlainTextCell(customer.getCity().getCountry().getName());
    }

如需以编程的方式注册列生成处理器,使用 Table 组件的 addGeneratedColumn() 方法。该方法需要两个参数:列的标识符和 Table.ColumnGenerator 接口的实现。如果标识符可以匹配 XML 描述中为表格列设置的标识符,则用新列代替 XML 中定义的列。如果标识符与任何列都不匹配,则会在右侧添加新列。

Table.ColumnGenerator 接口的 generateCell() 方法与上面介绍的 columnGenerator 处理器等效:接收对应渲染行的实体实例作为参数,返回在单元格中需要展示的可视化组件。

列值导出

使用 表格导出 扩展组件可以将 Table 组件的内容导出成支持的文件类型。

安装完组件后,可以为表格定义 excelExportjsonExport 操作,也可使用 表格导出器

如过使用了自定义生成列,则默认不会导出这些列的内容。参考 导出带生成列的表格 中的示例。

下面的例子中,在使用 excelExport 操作导出时,为数据的某一列设置了自定义的输出。

界面描述:

<table id="printableTable"
       width="100%"
       dataContainer="customersDc1">
    <actions>
        <action id="excelExport" type="excelExport"/>
    </actions>
</table>

界面控制器:

@Named("printableTable.excelExport")
protected ExcelExportAction printableTableExcelExport;

@Subscribe
public void onInit(InitEvent event) {
    printableTableExcelExport.addColumnValueProvider("firstName", context -> { (1)
        Customer customer = context.getEntity();
        return "Name: " + customer.getFirstName();
    });
}
1 该方法一个参数是列标识符,第二个是从列中获取展示值的函数。

表格编辑

表格可以配置支持行内编辑。

editable 属性可以将表格转换至编辑模式。

在这种模式下,具有 editable = true 属性的列显示用于编辑相应实体属性的组件。运行时无法修改此属性设置。

根据相应实体属性的类型自动选择每个可编辑列的组件类型。例如,对于字符串和数字类型的属性,使用 TextField,日期时间 - DateField,枚举 - ComboBox,实体引用 - EntityPicker

对于 Date 类型的可编辑列,还可以定义 dateFormatresolution 属性,与 DateField 中相同属性类似。

可以为显示关联实体的可编辑列定义 optionsContainercaptionProperty 属性。如果设置了 optionsContainer 属性,应用程序将使用 ComboBox 而不是 EntityPicker

右键菜单

在表格中点击右键可以激活右键菜单。

contextMenuEnabled 属性可以开启右键菜单。默认值为 true。右键菜单展示 表格操作(如果有的话)。

table context menu

样式

可以在界面 XML 或者控制器中使用 stylename 属性为 Table 组件设置预定义样式:

<table id="tableBorderless"
       caption="Table with borderless style"
       width="100%"
       stylename="borderless"
       dataContainer="customersDc1">
tableBorderless.setStyleName(ThemeClassNames.TABLE_BORDERLESS);

预定义样式:

  • borderless - 删除表格外边框;

  • no-header - 隐藏表格列的表头;

  • no-horizontal-lines - 删除行之间的水平分隔线;

  • no-vertical-lines - 删除列之间的垂直分隔线;

  • no-stripes - 删除行间隔背景色。

Table 的外观可以使用带 $jmix-table-* 前缀的 SCSS 变量进行自定义。在创建了 自定义主题 之后,可以在可视化编辑器中修改这些变量。

Table 接口方法

  • getSelected()getSingleSelected() 返回表格中的选定行对应的实体实例。调用 getSelected() 方法来获取实例集合。如果未选择任何内容,则程序将返回空集。如果禁用了 multiselect,应该使用 getSingleSelected() 方法返回一个选定实体,如果没有选择任何内容则返回 null

  • requestFocus() 方法允许将焦点设置在某一行的具体的可编辑字段上。需要两个参数:表示行的实体实例和列的标识符。请求焦点的示例如下:

    table.requestFocus(item, "count");
  • scrollTo() 方法允许将表格滚动到具体行。需要一个参数:表示行的实体实例。

    滚动条的示例:

    table.scrollTo(item);
  • setItemClickAction() 方法能够定义一个双击表格行时执行的 操作。如果未定义此操作,表格将尝试按以下顺序在其操作列表中查找适当的操作:

    • shortcut 属性指定给 Enter 键的操作;

    • edit 操作

    • view 操作

      如果找到此操作,并且操作具有 enabled=true 属性,则执行该操作。

      下面示例为 XML 中 id 是 tableClickTable 组件设置了 ItemClickAction

      @Autowired
      private Table<Customer> tableClick;
      
      @Subscribe
      public void onInit(InitEvent event) {
          tableClick.setItemClickAction(new BaseAction("itemClickAction")
                  .withHandler(actionPerformedEvent -> {
                      Customer customer = tableClick.getSingleSelected();
                      if (customer != null) {
                          notifications.create()
                                  .withCaption("Item clicked for: " + customer.getFirstName()+
                                          "" + customer.getLastName())
                                  .show();
                      }
                  }));
      }
  • setEnterPressAction() 方法可以定义按下 Enter 键时执行的操作。如果未定义此操作,则表将尝试按以下顺序在其操作列表中查找适当的操作:

    • setItemClickAction() 方法定义的动作;

    • shortcut 属性指定给 Enter 键的操作;

    • edit 操作;

    • view 操作;

      如果找到此操作,并且操作具有 enabled=true 属性,则执行该操作。

      下面示例为 XML 中 id 是 tableClickTable 组件设置了 ItemClickAction

      @Autowired
      private Table<Customer> tableClick;
      
      @Subscribe
      public void onInit(InitEvent event) {
          tableClick.setEnterPressAction(new BaseAction("enterPressAction")
                  .withHandler(actionPerformedEvent -> {
                      Customer customer = tableClick.getSingleSelected();
                      if (customer != null) {
                          notifications.create()
                                  .withCaption("Enter pressed for: " + customer.getFirstName()+
                                          "" + customer.getLastName())
                                  .show();
                      }
                  }));
      }
  • The getAggregationResults() 方法返回 聚合 结果的 map,key 为 Table 的列标识符,value 为聚合值。

事件和处理器

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

或者可以使用界面控制器顶部面板的 Generate Handler 按钮。

AggregationDistributionProvider

定义在表格行间按照自定义算法分发聚合值的规则。如果用户在聚合单元格输入值,会根据自定义的算法将值分发到贡献至该聚合值的单元格。只支持 TOP 聚合样式。如果要使得聚合单元格可编辑,需要使用 xml 中 aggregation 元素的 editable 属性。

当创建 provider 时,应当使用 AggregationDistributionContext<E> 对象,包含分发聚合值所需的数据:

  • Column column 合计或分组聚合值变更的列;

  • Object value - 新的聚合值;

  • Collection<E> scope - 一组实体,会受到聚合值的影响;

  • boolean isTotalAggregation 显示合计聚合值或者分组聚合值。

作为示例,我们考虑一个展示预算的表格。用户创建预算种类,并设置每种预算在收入中需要占百分比。下一步,用户在聚合单元格设置收入的总额,然后会按照不同的种类分发。

界面 XML 描述中表格的配置示例:

<table id="budgetTable"
       width="100%"
       aggregatable="true"
       dataContainer="budgetItemsDc">
    <columns>
        <column id="category"/>
        <column id="percent"/>
        <column id="amount">
            <aggregation type="SUM"
                         editable="true"/>
        </column>
    </columns>
</table>

界面控制器示例:

@Install(to = "budgetTable", subject = "aggregationDistributionProvider")
private void budgetTableAggregationDistributionProvider(
        Table.AggregationDistributionContext<BudgetItem> context) {
    Collection<BudgetItem> scope = context.getScope();
    if (scope.isEmpty()) {
        return;
    }

    double value = context.getValue() != null ?
            ((double) context.getValue()) : 0;

    for (BudgetItem budgetItem : scope) {
        budgetItem.setAmount(value / 100 * budgetItem.getPercent());
    }
}
table aggregation budget

如需以编程的方式注册聚合值分配 provider,使用组件的 setAggregationDistributionProvider() 方法。

ColumnCollapseEvent

ColumnCollapseEvent列可见性 变更时发送。

下面示例为 XML 中 id 是 tableCollapsedTable 订阅了该事件:

@Subscribe("tableCollapsed")
public void onTableCollapsedColumnCollapse(Table.ColumnCollapseEvent<Customer> event) {
    notifications.create()
            .withCaption((event.isCollapsed() ? "Collapsed: " : "Expanded: ") +
                    event.getColumn().getCaption())
            .show();
}

如需以编程的方式注册事件处理器,使用组件的 addColumnCollapseListener() 方法。

ColumnReorderEvent

ColumnReorderEvent 当用户重排表格列时发送。

下面示例为 XML 中 id 是 tableReorderTable 订阅了该事件:

@Subscribe("tableReorder")
public void onTableReorderColumnReorder(Table.ColumnReorderEvent<Customer> event) {
    notifications.create()
            .withCaption("Columns were reordered!")
            .show();
}

如需以编程的方式注册事件处理器,使用组件的 addColumnReorderListener() 方法。

ContextHelpIconClickHandler

IconProvider

图标 provider 支持在每行的开头加一个图标:

@Install(to = "tableWithIcons", subject = "iconProvider")
private String tableWithIconsIconProvider(Customer customer) {
    return customer.getEmail() != null ?
            JmixIcon.MAIL_FORWARD.source() : JmixIcon.CANCEL.source();
}
table icon provider

如需以编程的方式注册图标的 provider,使用组件的 setIconProvider() 方法。

ItemDescriptionProvider

当用户鼠标悬停于某个单元格之上时,内容描述 provider 会生成描述提示框。

下面例子中,我们展示了为 tableWithDescription 使用 ItemDescriptionProvider

@Install(to = "tableWithDescription", subject = "itemDescriptionProvider")
private String tableWithDescriptionItemDescriptionProvider(
        Customer customer, String property) {
    if (property == null)
        return null;
    else if (property.equals("rewardPoints")) {
        return "Reward points are a part of the loyalty program affecting the rating of the " +
                customer.getFirstName() + " " + customer.getLastName();
    } else if (property.equals("level")) {
        switch (customer.getLevel()) {
            case SILVER:
                return "The customer gets special offers from sellers and birthday congratulations";
            case GOLD:
                return "The customer gets 2 coupons with a rating of $ 1";
            case PLATINUM:
                return "The customer gets a coupons with a par value of $ 3";
            case DIAMOND:
                return "The customer gets a coupon with a par value of $ 5";
        }
    }
    return null;
}
table item description

LookupSelectHandler

LookupSelectHandler 是当用户在查找界面选中一行数据按下 Enter 或者双击一行时调用。接收选中的实体集合作为参数。可以定义如下:

@Install(to = "tableLookupSelect", subject = "lookupSelectHandler")
private void tableLookupSelectLookupSelectHandler(Collection<Customer> collection) {
    checkCustomers(collection);
}

如需以编程的方式注册查找界面选择处理器,使用组件的 setLookupSelectHandler() 方法。

SelectionEvent

SelectionEvent 当选择变更时发送。

下面示例为 XML 中 id 是 tableSelectEventTable 订阅了该事件:

@Autowired
private Table<Customer> tableSelectEvent;

@Subscribe("tableSelectEvent")
public void onTableSelectEventSelection(Table.SelectionEvent<Customer> event) {
    Customer customer = tableSelectEvent.getSingleSelected();
    notifications.create()
            .withCaption("You selected " + customer.getFirstName() +
                    " " + customer.getLastName() + " customer")
            .show();
}

如需以编程的方式注册事件处理器,使用组件的 addSelectionListener() 方法。

StyleProvider

StyleProvider 方法可以设置表格单元格显示样式。表格的每一行和每个单元分别调用这个 provider。如果某一行调用该方法,则第一个参数包含该行显示的实体实例,第二个参数为 null。如果单元格调用该方法,则第二个参数包含单元格显示的属性的名称。

设置样式的示例:

@Install(to = "styledTable", subject = "styleProvider")
private String styledTableStyleProvider(Customer entity, String property) {
    if (property == null) {
        if (Boolean.TRUE.equals(entity.getEmail() != null)) {
            return "customer-has-email";
        }
    } else if (property.equals("level")) {
        switch (entity.getLevel()) {
            case SILVER:
                return "level-silver";
            case GOLD:
                return "level-gold";
            case PLATINUM:
                return "level-platinum";
            case DIAMOND:
                return "level-diamond";
        }
    }
    return null;
}

然后应该在应用程序主题中设置的单元格和行样式。有关创建主题的详细信息,请参阅 主题。在控制器中定义的 provider 返回的样式名称作为 CSS 选择器。示例:

.customer-has-email {
    font-weight: bold;
}

.level-silver {
    background-color: #f2f2f2;
    color: black;
}

.level-gold {
    background-color: #ffda79;
    color: black;
}

.level-platinum {
    background-color: #637497;
    color: white;
}

.level-diamond {
    background-color: #8befff;
    color: black;
}
table style provider

如需以编程的方式注册样式 provider,使用组件的 setStyleProvider() 方法。