3.5.2.1.11. 数据网格
本章内容:
DataGrid - 数据网格组件,与 表格 组件类似, 适合用于展示、分类、排序表格类数据,由于使用了在滚动时加载数据的延迟加载方式,所以此组件具有更好的数据行、列操作性能。
 
  该组件的 XML 名称为 dataGrid
以下为在 XML 文件中定义数据网格的示例:
<data>
    <collection id="ordersDc" class="com.company.sales.entity.Order" view="order-with-customer">
        <loader id="ordersDl">
            <query>
                <![CDATA[select e from sales_Order e order by e.date]]>
            </query>
        </loader>
    </collection>
</data>
<layout>
    <dataGrid id="ordersDataGrid" dataContainer="ordersDc" height="100%" width="100%">
        <columns>
            <column id="date" property="date"/>
            <column id="customer" property="customer.name"/>
            <column id="amount" property="amount"/>
        </columns>
    </dataGrid>
</layout> 
  其中 <column> 元素里的 id 属性是列的标识,property 指示数据容器实体中的属性,对应的数据库中的数据会展示在该列。
如需以编程的方式在界面控制器定义数据源,则可以在 XML 中使用 metaClass 属性替换声明式的设置 dataContainer。
dataGrid 元素
-  
columns- 必要元素,定义DataGrid的所有列。columns元素有如下属性:-  
includeAll– 加载 dataContainer 中定义的 view 的所有属性。在下面的例子中,我们显示了
customersDc中使用视图的所有属性。如果视图包含系统属性,也同样会显示。<dataGrid id="dataGrid" width="100%" height="100%" dataContainer="customersDc"> <columns includeAll="true"/> </dataGrid>如果实体的视图包含引用属性,该属性会按照其实例名称进行展示。如果需要展示一个特别的属性,则需要在视图和
column元素中定义:<columns includeAll="true"> <column id="address.street"/> </columns>如果未指定视图,
includeAll会加载给定实体及其祖先的所有属性。 
-  
exclude– 英文逗号分隔的属性列表,这些属性不会被加载到数据网格。在下面的例子中,我们会显示除了
name和order之外的所有属性:<dataGrid id="dataGrid" width="100%" height="100%" dataContainer="customersDc"> <columns includeAll="true" exclude="name, order"/> </dataGrid> 
每一列是在嵌套的
column元素中描述,该元素有如下属性:-  
id- 非必须属性,标识一列。如果没有设置,对应的property值会被用作该列的标识,所以这种时候property值是必须的。否则会抛出GuiDevelopmentException异常。如果列是在界面控制器代码中创建的,则id属性是必须的。 
-  
property- 指对应的实体属性。可以是数据源/数据容器实体的属性,也可以是关联实体的属性,关联实体属性前面需要加上关联类名字并通过“.”连接。例如:<columns> <column id="date" property="date"/> <column id="customer" property="customer"/> <column id="customerName" property="customer.name"/> <column id="customerCountry" property="customer.address.country"/> </columns> -  
caption- 可选属性,定义列标题。如果未设置,对应的本地化属性名称会被做为列标题显示。 
-  
expandRatio- 设置列宽占比。默认情况下,所有列等宽(expandRatio = 1)。如果至少有一列设置了其它值,则忽略所有的隐式值,并且只使用设置的值。 
-  
collapsible- 定义用户是否可以通过DataGrid表格组件右上角的侧边栏菜单隐藏/显示该列。默认为true。 
-  
collapsed- 可选属性,设置为true时自动隐藏该列。该属性默认值为false。 
-  
collapsingToggleCaption- 设置在侧边栏菜单中该列的标题。默认为null, 此时侧边栏菜单中该列的标题与数据网格中该列的标题一致。
 
           
-  
resizable- 定义用户是否可以调整列宽。 
-  
sortable- 可选属性,可以用来关闭针对该列的排序。当整个DataGrid数据网格控件的sortable属性设置为true(默认值)时生效。 -  
width- 可选属性,定义列宽。只支持以像素为单位的数值类型。 
-  
minimumWidth- 设置最小列宽,以像素为单位。 
-  
maximumWidth- 设置最大列宽,以像素为单位。 
<column id="date" property="date"> <formatter class="com.haulmont.cuba.gui.components.formatters.DateFormatter" format="yyyy-MM-dd HH:mm:ss" useUserTimezone="true"/> </column> -  
 
-  
rowsCount- 可选元素,会为数据网格控件创建一个行数(RowsCount)控件。行数控件会启用数据分页,在界面控制器中调用CollectionLoader.setMaxResults()方法可以控制数据加载器中的数据量,进而能控制每页最大行数。另外,绑定到相同数据源的通用过滤器组件也能实现此功能。rowsCount控件也会显示数据结果总数,但不需要把这些数据全部加载出来。用户可以点击 "?" 按钮, 它会调用com.haulmont.cuba.core.global.DataManager#getCount方法,该方法使用相同的参数请求数据库,同时使用COUNT(*)聚合函数代替加载数据。返回的数值会显示在 "?" 位置。RowsCount组件的autoLoad属性如果设置为true,启用自动加载行数。可以在 XML 描述中设置:<rowsCount autoLoad="true"/>另外,在界面控制器中也可以通过
RowsCountAPI 启用或禁用该功能:boolean autoLoadEnabled = rowsCount.getAutoLoad(); rowsCount.setAutoLoad(false); 
dataGrid 属性
-  
aggregatable属性可以启用对DataGrid的行进行聚合运算,支持下列运算符:-  
SUM− 和 -  
AVG− 均值 -  
COUNT− 计数 -  
MIN− 最小值 -  
MAX− 最大值 
聚合
DataGrid列的aggregation元素需要设置type属性,表示聚合的函数。 默认情况下,聚合列只支持数字类型,比如Integer、Double、Long和BigDecimal。聚合值会显示在DataGrid顶部的附加行内。聚合的功能与 表格 组件一致。也就是说,同样可以使用 strategyClass、valueDescription 和 formatter。带聚合列的
DataGridXML 描述示例:<dataGrid id="ordersDataGrid" dataContainer="ordersDc" aggregationPosition="BOTTOM" aggregatable="true"> <columns> <column id="customerGrade" property="customer.grade"> <aggregation strategyClass="com.company.sample.CustomerGradeAggregation" valueDescription="msg://customerGradeAggregationDesc"/> </column> <column id="amount" property="amount"> <aggregation type="SUM"> <formatter class="com.company.sample.MyFormatter"/> </aggregation> </column> ... </columns> ... </dataGrid> -  
 
-  
aggregationPosition属性可以设置聚合值行的位置:TOP或BOTTOM。默认为TOP。 
-  
columnResizeMode- 设置调整列宽时的动画效果。支持两种效果:-  
ANIMATED- 动画效果,列宽跟随鼠标拖拽(默认)。 -  
SIMPLE- 简单效果,列宽会在拖拽动作结束后才发生改变。 
列宽变化事件可以通过监听器
ColumnResizeListener跟踪。可以使用 isUserOriginated() 方法跟踪列宽变化事件的来源。 -  
 
-  
columnsCollapsingAllowed- 定义用户是否可以在表格侧边菜单中隐藏/折叠某些列。侧边菜单中,显示的列会标记打勾。其他菜单项:-  
Select all− 显示所有列 -  
Deselect all− 隐藏所有列
 
        当列名选中/非选中是,每列的
collapsed属性会更新。当columnsCollapsingAllowed为false时,列的collapsed属性就不能被设置为true。列折叠状态的变化可以通过监听器
ColumnCollapsingChangeListener跟踪。列折叠事件的来源可以使用 isUserOriginated() 方法进行跟踪. 
 -  
 
-  
contextMenuEnabled- 开启或关闭右键菜单。默认为true。DataGrid数据网格控件的右键点击事件可以通过监听器ContextClickListener跟踪。 
-  
editorBuffered- 编辑器缓冲模式开启或关闭。默认为true。 
-  
editorCancelCaption- 设置DataGrid数据网组件编辑器中取消(cancel)按钮的名称。 
-  
editorCrossFieldValidate- 在行内编辑器启用跨字段验证。默认为true。 
-  
editorEnabled- 启用数据项的行内编辑器。默认为false。如果数据网格组件是跟 KeyValueCollectionContainer 绑定的,则该数据是只读的,此时设置editorEnabled属性便没有意义。 
-  
editorSaveCaption- 设置数据网格组件编辑器中保存(save)按钮的名称。 
-  
frozenColumnCount- 设置固定列的个数。0表示不需要固定任何列,除了开启多选模式时的选择列。设为-1的时候即使选择列也不固定。 
-  
headerVisible- 定义是否显示表头。默认为true。 
-  
htmlSanitizerEnabled- 启用或禁用 HTML 清理。DataGrid组件有些 provider 可以渲染 HTML:-  
HtmlRenderer -  
RowDescriptionProvider,在设置了
ContentMode.HTML时。 -  
DescriptionProvider 在设置了
ContentMode.HTML时。当
htmlSanitizerEnabled属性设置为true时,这些 provider 的执行结果会被清理,返回安全的 HTML。protected static final String UNSAFE_HTML = "<i>Jackdaws </i><u>love</u> <font size=\"javascript:alert(1)\" " + "color=\"moccasin\">my</font> " + "<font size=\"7\">big</font> <sup>sphinx</sup> " + "<font face=\"Verdana\">of</font> <span style=\"background-color: " + "red;\">quartz</span><svg/onload=alert(\"XSS\")>"; @Inject private DataGrid<Customer> customersDataGrid; @Inject private DataGrid<Customer> customersDataGrid2; @Inject private DataGrid<Customer> customersDataGrid3; @Subscribe public void onInit(InitEvent event) { customersDataGrid.setHtmlSanitizerEnabled(true); customersDataGrid.getColumn("name") .setRenderer(customersDataGrid.createRenderer(DataGrid.HtmlRenderer.class)); customersDataGrid2.setHtmlSanitizerEnabled(true); customersDataGrid2.setRowDescriptionProvider(customer -> UNSAFE_HTML, ContentMode.HTML); customersDataGrid3.setHtmlSanitizerEnabled(true); customersDataGrid3.getColumn("name").setDescriptionProvider(customer -> UNSAFE_HTML, ContentMode.HTML); }htmlSanitizerEnabled属性会覆盖全局的 cuba.web.htmlSanitizerEnabled 配置。如果使用
HtmlRenderer时,想用自定义的presentationProvider,则展示的值默认不会被清理。如需清理 HTML,则需要手动做一下:protected static final String UNSAFE_HTML = "<i>Jackdaws </i><u>love</u> <font size=\"javascript:alert(1)\" " + "color=\"moccasin\">my</font> " + "<font size=\"7\">big</font> <sup>sphinx</sup> " + "<font face=\"Verdana\">of</font> <span style=\"background-color: " + "red;\">quartz</span><svg/onload=alert(\"XSS\")>"; @Inject private DataGrid<Customer> customersDataGrid; @Inject private HtmlSanitizer htmlSanitizer; @Subscribe public void onInit(InitEvent event) { customersDataGrid.getColumn("name") .setRenderer(customersDataGrid.createRenderer(DataGrid.HtmlRenderer.class), (Function<String, String>) nameValue -> htmlSanitizer.sanitize(UNSAFE_HTML)); } 
 -  
 
-  
reorderingAllowed- 定义用户是否可以通过鼠标拖拽重新设置列的顺序。默认值为true。列排序的改变事件可以通过监听器
ColumnReorderListener跟踪。排序改变事件的来源可以通过 isUserOriginated() 方法跟踪。 
-  
selectionMode- 设置行选择模式,支持以下四种:-  
SINGLE- 单行选择。 -  
MULTI- 多行选择。 -  
MULTI_CHECK- 通过内嵌复选框列进行多选。 -  
NONE- 不支持选择。行选中事件可以通过监听器
SelectionListener跟踪。行选中事件的来源可以使用 isUserOriginated() 方法跟踪.
 
           
 -  
 
-  
sortable- 开启/关闭数据网格控件的排序功能。默认为true。开启后,点击列名会在列名右边显示排序图标。使用列的sortable属性可以禁用该列的排序功能。DataGrid的排序事件可以通过监听器SortListener跟踪。排序事件的来源可以通过 isUserOriginated() 方法跟踪。 
-  
textSelectionEnabled- 开启/关闭数据网格单元格中的文字选择功能。默认为false。 
DataGrid 接口方法
-  
getColumns()- 按当前界面的展示顺序获取列集合。 -  
getSelected()、getSingleSelected()- 返回所选行对应实体的实例。getSelected() 返回一个集合。如果没有选择任何行,则返回一个空的集合。如果设置的是SelectionMode.SINGLE单选模式,用 getSingleSelected() 会更方便,它直接返回一个被选择的实体实例,或者 null(没有选择任何行)。 -  
getVisibleColumns()- 按当前界面中列的显示顺序获取用户可见的列集合。 
-  
scrollTo()- 将DataGrid滚动到指定行。需要一个实体实例做为输入参数来指定滚动到哪一行。除了实体实例参数,另有重载方法支持ScrollDestination参数,该参数可以为以下值:-  
ANY- 滚动尽量少的位置来展示所需要的数据。 -  
START- 滚动DataGrid,使所需要的数据展示在可见部分的顶端。 -  
MIDDLE- 滚动DataGrid,使所需要的数据展示在可见部分的中部。 -  
END- 滚动DataGrid,使所需要的数据展示在可见部分的底部。 
 -  
 -  
scrollToStart()andscrollToEnd()- 将DataGrid滚动到开头或结尾。 
-  
addCellStyleProvider()- 为DataGrid单元格添加 style provider。 
-  
addRowStyleProvider()- 为DataGrid行添加 style provider。 
-  
setEnterPressAction()- 设置按下 回车键 时需要执行的操作。如果没有定义这种操作,控件会尝试按以下顺序找一个合适的操作:-  
setItemClickAction()方法定义的操作。 -  
通过
shortcut快捷键属性定义给 回车键 的操作。 -  
edit(编辑)操作。 -  
view(查看)操作。 
如果找到一个操作,并且其属性
enabled=true,则会执行它。 -  
 
-  
setItemClickAction()- 设置双击时的操作。如果没有定义,组件会按以下顺序找一个合适的操作:-  
通过
shortcut快捷键属性定义给 回车键 的操作。 -  
edit(编辑)操作。 -  
view(查看)操作。 
如果找到一个操作并且属性
enabled=true,则会执行它。单击事件可以通过监听器
ItemClickListener跟踪。 -  
 
-  
sort()- 根据指定列对数据进行排序,通过枚举值SortDirection控制排序方式:-  
ASCENDING- 升序 (A-Z, 1..9)。 -  
DESCENDING- 降序 (Z-A, 9..1)。 
 -  
 
-  
getAggregationResults()方法返回聚合结果的映射(map),键值为DataGrid的列标识符,值为聚合值。 
使用 description providers
-  
setDescriptionProvider()方法用来为每个DataGrid列的单元格生成可选的描述(提示)。描述支持 HTML 标记。@Inject private DataGrid<Customer> customersDataGrid; @Subscribe protected void onInit(InitEvent event) { customersDataGrid.getColumnNN("age").setDescriptionProvider(customer -> getPropertyCaption(customer, "age") + customer.getAge(), ContentMode.HTML); customersDataGrid.getColumnNN("active").setDescriptionProvider(customer -> getPropertyCaption(customer, "active") + getMessage(customer.getActive() ? "trueString" : "falseString"), ContentMode.HTML); customersDataGrid.getColumnNN("grade").setDescriptionProvider(customer -> getPropertyCaption(customer, "grade") + messages.getMessage(customer.getGrade()), ContentMode.HTML); }
 
        
-  
setRowDescriptionProvider()方法用来为每个DataGrid行生成可选的描述(提示)。如果同时也设置了列描述提供者,只有在列描述提供者返回 null 时显示行描述提供器实例。customersDataGrid.setRowDescriptionProvider(Instance::getInstanceName);
 
        
使用 DetailsGenerator 接口
使用 setDetailsGenerator() 方法设置 DetailsGenerator 接口,可以生成自定义控件来展示对应行的明细:
@Inject
private DataGrid<Order> ordersDataGrid;
@Inject
private UiComponents uiComponents;
@Install(to = "ordersDataGrid", subject = "detailsGenerator")
protected Component ordersDataGridDetailsGenerator(Order order) {
    VBoxLayout mainLayout = uiComponents.create(VBoxLayout.NAME);
    mainLayout.setWidth("100%");
    mainLayout.setMargin(true);
    HBoxLayout headerBox = uiComponents.create(HBoxLayout.NAME);
    headerBox.setWidth("100%");
    Label infoLabel = uiComponents.create(Label.NAME);
    infoLabel.setHtmlEnabled(true);
    infoLabel.setStyleName("h1");
    infoLabel.setValue("Order info:");
    Component closeButton = createCloseButton(order);
    headerBox.add(infoLabel);
    headerBox.add(closeButton);
    headerBox.expand(infoLabel);
    Component content = getContent(order);
    mainLayout.add(headerBox);
    mainLayout.add(content);
    mainLayout.expand(content);
    return mainLayout;
}
private Component createCloseButton(Order entity) {
    Button closeButton = uiComponents.create(Button.class);
    // ... (1)
    return closeButton;
}
private Component getContent(Order entity) {
    Label<String> content = uiComponents.create(Label.TYPE_STRING);
    content.setHtmlEnabled(true);
    StringBuilder sb = new StringBuilder();
    // ... (2)
    content.setValue(sb.toString());
    return content;
} 
  | 1 | – 参考 DataGridDetailsGeneratorSample 类中的 createCloseButton 方法全部代码。 |  
    
| 2 | – 参考 DataGridDetailsGeneratorSample 类中的 getContent 方法全部代码。 |  
    
结果如图所示:
 
  使用 DataGrid 行内编辑器
DataGrid 组件支持行内编辑器来编辑单元格数据。当用户要编辑一个数据项时,行内编辑界面会显示并自带默认的保存和取消按钮。
行内编辑器对应的方法有:
-  
getEditedItem()- 返回正在被编辑的数据项。 -  
isEditorActive()- 是否正在行内编辑界面编辑某个数据项。 
-  
editItem(Object itemId)(废弃) - 为提供了id的数据项打开编辑界面。如果数据项在当前界面区域不可见,数据网格会将数据项滚动到可视区域。 
-  
edit(Entity item)- 为指定的数据项打开编辑界面。如果数据项在当前界面区域不可见,数据网格会将数据项滚动到可视区域。 
DataGrid 行内编辑器可以使用实体约束(跨字段验证)。如果有验证错误,DataGrid 会显示错误消息。开启/禁用该功能或者获取当前状态可以使用下面方法:
-  
setEditorCrossFieldValidate(boolean validate)- 启用、禁用行内编辑器的跨字段验证。默认为true。 -  
isEditorCrossFieldValidate()- 如果行内编辑器的跨字段验证开启,则返回true。 
使用以下方法添加/删除行内编辑界面打的监听器:
-  
addEditorOpenListener(),removeEditorCloseListener()- 添加/删除行内编辑界面打开监听器。当用户双击
DataGrid数据网格中某个区域时,行内编辑界面打开,使用上述监听器,可以获取被编辑行的其它字段并进行需要的修改。这种方法可以使得不用关闭当前行内编辑器就能修改其它字段。例如:
customersTable.addEditorOpenListener(editorOpenEvent -> { Map<String, Field> fieldMap = editorOpenEvent.getFields(); Field active = fieldMap.get("active"); Field grade = fieldMap.get("grade"); ValueChangeListener listener = e -> active.setValue(true); grade.addValueChangeListener(listener); }); 
-  
addEditorCloseListener(),removeEditorCloseListener()- 添加/删除行内编辑界面关闭监听器。 
-  
addEditorPreCommitListener(),removeEditorPreCommitListener()- 添加/删除行内编辑界面数据提交前监听器。 
-  
addEditorPostCommitListener(),removeEditorPostCommitListener()- 添加/删除行内编辑界面数据提交后监听器。 
行内编辑器所做的数据修改只提交到数据源或者数据容器。需要额外的代码把他们持久化到数据库。
可以通过 EditorFieldGenerationContext 类对编辑器组件进行定制,在某一列上使用 setEditFieldGenerator() 方法设置该列数据的编辑器组件:
@Inject
private DataGrid<Order> ordersDataGrid;
@Inject
private UiComponents uiComponents;
@Subscribe
protected void onInit(InitEvent event) {
    ordersDataGrid.getColumnNN("amount").setEditFieldGenerator(orderEditorFieldGenerationContext -> {
        LookupField<BigDecimal> lookupField = uiComponents.create(LookupField.NAME);
        lookupField.setValueSource((ValueSource<BigDecimal>) orderEditorFieldGenerationContext
                .getValueSourceProvider().getValueSource("amount"));
        lookupField.setOptionsList(Arrays.asList(BigDecimal.ZERO, BigDecimal.ONE, BigDecimal.TEN));
        return lookupField;
    });
} 
  结果如下:
 
  使用 ColumnGenerator 接口
DataGrid 组件可以添加自定义列,有两种方式:
-  
声明式,在界面控制器使用
@Install注解:@Inject private UiComponents uiComponents; @Install(to = "dataGrid.fullName", subject = "columnGenerator") protected Component fullNameColumnGenerator(DataGrid.ColumnGeneratorEvent<Customer> e) { Label<String> label = uiComponents.create(Label.TYPE_STRING); label.setValue(e.getItem().getFirstName() + " " + e.getItem().getLastName()); return label; }ColumnGeneratorEvent包含实体信息以及列标识符,该实体显示在DataGrid的当前行。 -  
使用下面的方法编程创建:
-  
addGeneratedColumn(String columnId, ColumnGenerator generator) -  
addGeneratedColumn(String columnId, ColumnGenerator generator, int index) 
ColumnGenerator是用来定义生成的列或者计算出的列的接口:-  
该列每一行的数据值,
 -  
该列数据类型。
 
下面是一个生成列的示例,这个列显示大写的用户登录名:
@Subscribe protected void onInit(InitEvent event) { DataGrid.Column column = usersGrid.addGeneratedColumn("loginUpperCase", new DataGrid.ColumnGenerator<User, String>(){ @Override public String getValue(DataGrid.ColumnGeneratorEvent<User> event){ return event.getItem().getLogin().toUpperCase(); } @Override public Class<String> getType(){ return String.class; } }, 1); column.setCaption("Login Upper Case"); }结果如下:
 
       默认情况下,新生成的列加在数据网格的最右边。有两种方法可以管理列的位置:代码中使用 index 或者在界面 XML 文件中提前定义好并设置
id, 然后在addGeneratedColumn方法中使用该 id。 -  
 
使用 renderers
数据在列中的显示方式可以使用带参数的 renderer 以声明式的方法自定义。一些 DataGrid 的 renderer 通过特定的 XML 元素设置,并且定义了对应的属性作为参数。对非自定义生成列,可以声明 renderer。
平台支持的 renderer 列表:
-  
ButtonRenderer– 以字符串值形式展示按钮标题。ButtonRenderer不能在 XML 描述中定义,因为没有办法在 XML 描述中定义 renderer 点击监听器。 Studio 会在界面控制器的init()中生成ButtonRenderer的声明代码:@Inject private DataGrid<Customer> customersDataGrid; @Inject private Notifications notifications; @Subscribe public void onInit(InitEvent event) { DataGrid.ButtonRenderer<Customer> customersDataGridNameRenderer = customersDataGrid.createRenderer(DataGrid.ButtonRenderer.class); customersDataGridNameRenderer.setRendererClickListener(clickableButtonRendererClickEvent -> { notifications.create() .withType(Notifications.NotificationType.TRAY) .withCaption("ButtonRenderer") .withDescription("Column id: " + clickableButtonRendererClickEvent.getColumnId()) .show(); }); customersDataGrid.getColumn("name").setRenderer(customersDataGridNameRenderer); } 
-  
CheckBoxRenderer– 将 boolean 值展示为复选框图标。DataGrid的column元素有子元素checkBoxRenderer:<column property="checkBoxRenderer" id="checkBoxRendererColumn"> <checkBoxRenderer/> </column> 
-  
ClickableTextRenderer– 将普通的文本字符串显示为链接,并有回调处理器。ClickableTextRenderer不能在 XML 描述中定义,因为没有办法在 XML 描述中定义 renderer 点击监听器。 Studio 会在界面控制器的init()中生成ClickableTextRenderer的声明代码:@Inject private DataGrid<Customer> customersDataGrid; @Inject private Notifications notifications; @Subscribe public void onInit(InitEvent event) { DataGrid.ClickableTextRenderer<Customer> customersDataGridNameRenderer = customersDataGrid.createRenderer(DataGrid.ClickableTextRenderer.class); customersDataGridNameRenderer.setRendererClickListener(clickableTextRendererClickEvent -> { notifications.create() .withType(Notifications.NotificationType.TRAY) .withCaption("ClickableTextRenderer") .withDescription("Column id: " + clickableTextRendererClickEvent.getColumnId()) .show(); }); customersDataGrid.getColumn("name").setRenderer(customersDataGridNameRenderer); } 
-  
ComponentRenderer– UI 组件 rendererDataGrid的column元素有子元素componentRenderer:<column property="componentRenderer" id="componentRendererColumn"> <componentRenderer/> </column> 
-  
DateRenderer– 用定义的格式显示日期DataGrid的column元素有子元素dateRenderer,该元素有非必要的nullRepresentation属性和必填的format字符串属性:<column property="dateRenderer" id="dateRendererColumn"> <dateRenderer nullRepresentation="null" format="yyyy-MM-dd HH:mm:ss"/> </column> 
-  
IconRenderer– 展示CubaIcon的 renderer。DataGrid的column元素有子元素iconRenderer:下面的例子展示将实体
String类型的属性渲染成CubaIcon:<column id="iconOS" property="iconOS"> <iconRenderer/> </column>@Install(to = "devicesTable.iconOS", subject = "columnGenerator") private Icons.Icon devicesTableIconOSColumnGenerator(DataGrid.ColumnGeneratorEvent<Device> event) { return CubaIcon.valueOf(event.getItem().getIconOS()); }结果如下:
 
      
-  
ImageRenderer– 使用图片的路径渲染图片。ImageRenderer不能在 XML 描述中定义,因为没有办法在 XML 描述中定义 renderer 点击监听器。 Studio 会在界面控制器的init()中生成ImageRenderer的声明代码:@Inject private DataGrid<TestEntity> testEntitiesDataGrid; @Inject private Notifications notifications; @Subscribe public void onInit(InitEvent event) { DataGrid.ImageRenderer<TestEntity> imageRenderer = testEntitiesDataGrid.createRenderer(DataGrid.ImageRenderer.class); imageRenderer.setRendererClickListener(imageRendererClickEvent -> notifications.create() .withType(Notifications.NotificationType.TRAY) .withCaption("ImageRenderer") .withDescription("Column id: " + imageRendererClickEvent.getColumnId()) .show()); testEntitiesDataGrid.getColumn("imageRendererColumn").setRenderer(imageRenderer); } 
-  
HtmlRenderer– 展示 HTMLDataGrid的column元素有子元素htmlRenderer,该元素有非必要的属性nullRepresentation:<column property="htmlRenderer" id="htmlRendererColumn"> <htmlRenderer nullRepresentation="null"/> </column> 
-  
LocalDateRenderer– 以LocalDate值显示日期DataGrid的column元素有子元素localDateRenderer,该元素有非必要的nullRepresentation属性和必填的format字符串属性:<column property="localDateRenderer" id="localDateRendererColumn"> <localDateRenderer nullRepresentation="null" format="dd/MM/YYYY"/> </column> 
-  
LocalDateTimeRenderer– 以LocalDateTime值显示日期。DataGrid的column元素有子元素localDateTimeRenderer,该元素有非必要的nullRepresentation属性和必填的format字符串属性:<column property="localDateTimeRenderer" id="localDateTimeRendererColumn"> <localDateTimeRenderer nullRepresentation="null" format="dd/MM/YYYY HH:mm:ss"/> </column> 
-  
NumberRenderer– 以定义的格式显示数字。DataGrid的column元素有子元素numberRenderer,该元素有非必要的nullRepresentation属性和必填的format字符串属性:<column property="numberRenderer" id="numberRendererColumn"> <numberRenderer nullRepresentation="null" format="%f"/> </column> 
-  
ProgressBarRenderer– 将 0~1 之间double类型的值展示为ProgressBar组件。DataGrid的column元素有子元素progressBarRenderer:<column property="progressBar" id="progressBarColumn"> <progressBarRenderer/> </column> 
-  
TextRenderer– 展示字符串DataGrid的column元素有子元素textRenderer,该元素有非必要的nullRepresentation属性:<column property="textRenderer" id="textRendererColumn"> <textRenderer nullRepresentation="null"/> </column> 
WebComponentRenderer 接口可以使得在数据网格单元格中显示不同的 Web 控件。以下是生成一个带查找控件的列的例子:
@Inject
private DataGrid<User> usersGrid;
@Inject
private UiComponents uiComponents;
@Inject
private Configuration configuration;
@Inject
private Messages messages;
@Subscribe
protected void onInit(InitEvent event) {
    Map<String, Locale> locales = configuration.getConfig(GlobalConfig.class).getAvailableLocales();
    Map<String, String> options = new TreeMap<>();
    for (Map.Entry<String, Locale> entry : locales.entrySet()) {
        options.put(entry.getKey(), messages.getTools().localeToString(entry.getValue()));
    }
    DataGrid.Column column = usersGrid.addGeneratedColumn("language",
            new DataGrid.ColumnGenerator<User, Component>() {
                @Override
                public Component getValue(DataGrid.ColumnGeneratorEvent<User> event) {
                    LookupField<String> component = uiComponents.create(LookupField.NAME);
                    component.setOptionsMap(options);
                    component.setWidth("100%");
                    User user = event.getItem();
                    component.setValue(user.getLanguage());
                    component.addValueChangeListener(e -> user.setLanguage(e.getValue()));
                    return component;
                }
                @Override
                public Class<Component> getType() {
                    return Component.class;
                }
            });
    column.setRenderer(new WebComponentRenderer());
} 
  结果如下:
 
  当字段类型与 renderer 支持的类型不匹配时,可以创建一个 Function 来匹配模型和视图的数据类型。比如,想把布尔类型用图标展示时,可以巧妙的使用 HtmlRenderer 来做 HTML 渲染以及实现布尔类型转换为图标展示的逻辑。
@Inject
private DataGrid<User> usersGrid;
@Subscribe
protected void onInit(InitEvent event) {
    DataGrid.Column<User> hasEmail = usersGrid.addGeneratedColumn("hasEmail", new DataGrid.ColumnGenerator<User, Boolean>() {
        @Override
        public Boolean getValue(DataGrid.ColumnGeneratorEvent<User> event) {
            return StringUtils.isNotEmpty(event.getItem().getEmail());
        }
        @Override
        public Class<Boolean> getType() {
            return Boolean.class;
        }
    });
    hasEmail.setCaption("Has Email");
    hasEmail.setRenderer(
        usersGrid.createRenderer(DataGrid.HtmlRenderer.class),
        (Function<Boolean, String>) hasEmailValue -> {
            return BooleanUtils.isTrue(hasEmailValue)
                    ? FontAwesome.PLUS_SQUARE.getHtml()
                    : FontAwesome.MINUS_SQUARE.getHtml();
        });
} 
  结果如下:
 
  Renderer 可以通过三种方式创建:
-  
声明式的通过
DataGrid的column元素的特定元素。 -  
在
DataGrid接口的 set 方法中直接设置 renderer 接口。 -  
为对应的模块直接创建 renderer 实现:
dataGrid.createRenderer(DataGrid.ImageRenderer.class) → new WebImageRenderer()目前,该方式只适合 Web 模块。
 
目前平台支持以下 renderer 接口:
Header 和 Footer
HeaderRow 和 FooterRow 接口受制于分别展示表头和表尾单元格,支持跨列合并单元格。
DataGrid 的以下方法用于创建和管理表头、表尾:
-  
appendHeaderRow()、appendFooterRow()- 在表头或表尾区底部添加一个新行。 -  
prependHeaderRow()、prependFooterRow()- 在表头或表尾区顶部添加一个新行。 -  
addHeaderRowAt()、addFooterRowAt()- 在表头或表尾区的指定位置添加新行。该位置及其后面的行位置顺序下移,行索引增加。 -  
removeHeaderRow()、removeFooterRow()- 从表头或表尾区删除指定行。 -  
getHeaderRowCount()、getFooterRowCount()- 获取表头或表尾区行数。 -  
setDefaultHeaderRow()- 设置表头默认行。默认表头行为用户提供排序功能。 
HeaderCell 和 FooterCell 接口提供自定义静态单元格功能:
-  
setStyleName()- 为单元格设置自定义样式。 -  
getCellType()- 返回单元格内容类型。静态单元格枚举类型DataGridStaticCellType有三个值:-  
TEXT- 文本 -  
HTML- HTML -  
COMPONENT- 组件 
 -  
 -  
getComponent()、getHtml()、getText()- 不同类型单元格获取内容的方法。 
下面这个例子中,表头包含合并的单元格,表尾显示经计算得出的值:
<dataGrid id="dataGrid" dataContainer="countryGrowthDs" width="100%">
    <columns>
        <column property="country"/>
        <column property="year2017"/>
        <column property="year2018"/>
    </columns>
</dataGrid> 
  @Inject
private DataGrid<CountryGrowth> dataGrid;
@Inject
private UserSessionSource userSessionSource;
@Inject
private Messages messages;
@Inject
private CollectionContainer<CountryGrowth> countryGrowthsDc;
private DecimalFormat percentFormat;
@Subscribe
protected void onBeforeShow(BeforeShowEvent event) {
    initPercentFormat();
    initHeader();
    initFooter();
    initRenderers();
}
private DecimalFormat initPercentFormat() {
    percentFormat = (DecimalFormat) NumberFormat.getPercentInstance(userSessionSource.getLocale());
    percentFormat.setMultiplier(1);
    percentFormat.setMaximumFractionDigits(2);
    return percentFormat;
}
private void initRenderers() {
    dataGrid.getColumnNN("year2017").setRenderer(new WebNumberRenderer(percentFormat));
    dataGrid.getColumnNN("year2018").setRenderer(new WebNumberRenderer(percentFormat));
}
private void initHeader() {
    DataGrid.HeaderRow headerRow = dataGrid.prependHeaderRow();
    DataGrid.HeaderCell headerCell = headerRow.join("year2017", "year2018");
    headerCell.setText("GDP growth");
    headerCell.setStyleName("center-bold");
}
private void initFooter() {
    DataGrid.FooterRow footerRow = dataGrid.appendFooterRow();
    footerRow.getCell("country").setHtml("<strong>" + messages.getMainMessage("average") + "</strong>");
    footerRow.getCell("year2017").setText(percentFormat.format(getAverage("year2017")));
    footerRow.getCell("year2018").setText(percentFormat.format(getAverage("year2018")));
}
private double getAverage(String propertyId) {
    double average = 0.0;
    List<CountryGrowth> items = countryGrowthsDc.getItems();
    for (CountryGrowth countryGrowth : items) {
        Double value = countryGrowth.getValue(propertyId);
        average += value != null ? value : 0.0;
    }
    return average / items.size();
} 
  
 
  DataGrid 样式
可以在 XML 描述中使用 stylename 属性为 DataGrid 组件设置预定义样式。
<dataGrid id="dataGrid"
          width="100%"
          height="100%"
          stylename="borderless"
          dataContainer="customersDc">
</dataGrid> 
  或者在界面控制器使用编程的方式设置。
dataGrid.setStyleName("borderless"); 
  预定义样式:
-  
borderless- DataGrid 无边线。 
-  
no-horizontal-lines- DataGrid 行之间无水平分割线。 
-  
no-vertical-lines- DataGrid 列之间无垂直分割线。 
-  
no-stripes- 每行背景颜色统一。 
- DataGrid 的属性列表
 -  
    
aggregatable - aggregationPosition - align - caption - captionAsHtml - colspan - columnResizeMode - columnsCollapsingAllowed - contextHelpText - contextHelpTextHtmlEnabled - contextMenuEnabled - css - dataContainer - description - descriptionAsHtml - editorBuffered - editorCancelCaption - editorCrossFieldValidate - editorEnabled - editorSaveCaption - emptyStateLinkMessage - emptyStateMessage - enable - box.expandRatio - frozenColumnCount - headerVisible - height - htmlSanitizerEnabled - icon - id - metaClass - reorderingAllowed - responsive - rowspan - selectionMode - settingsEnabled - sortable - stylename - tabIndex - textSelectionEnabled - visible - width
 - DataGrid 的元素
 -  
    
actions - buttonsPanel - columns - rowsCount
 - columns 元素属性列表
 - column 元素的属性列表
 -  
    
caption - collapsed - collapsible - collapsingToggleCaption - editable - expandRatio - id - maximumWidth - minimumWidth - property - resizable - sort - sortable - width
 - column 的元素
 -  
    
aggregation - checkBoxRenderer - componentRenderer - dateRenderer - formatter - iconRenderer - htmlRenderer - localDateRenderer - localDateTimeRenderer - numberRenderer - progressBarRenderer - textRenderer
 - aggregation 的属性
 - API
 -  
    
addGeneratedColumn - applySettings - createRenderer - edit - getAggregationResults - saveSettings - getColumns - setDescriptionProvider - addCellStyleProvider - setConverter - setDetailsGenerator - setEditorCrossFieldValidate - setEmptyStateLinkClickHandler - setEnterPressAction - setItemClickAction - setRenderer - setRowDescriptionProvider - addRowStyleProvider - sort
 - DataGrid 监听器
 -  
    
ColumnCollapsingChangeListener - ColumnReorderListener - ColumnResizeListener - ContextClickListener - EditorCloseListener - EditorOpenListener - EditorPostCommitListener - EditorPreCommitListener - ItemClickListener - SelectionListener - SortListener
 - 预定义样式
 -  
    
borderless - no-horizontal-lines - no-vertical-lines - no-stripes