DataGrid 数据网格
基本用法
一个典型的 dataGrid
如下所示:
-
按钮面板
-
排序按钮
-
分页器
-
列控制按钮
-
数据行
-
表头行
以下为在 XML 文件中定义 dataGrid
的示例:
<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>
<dataGrid id="customersGrid" width="100%" dataContainer="customersDc">
<actions>
<action id="create" type="create"/>
<action id="edit" type="edit"/>
<action id="remove" type="remove"/>
</actions>
<buttonsPanel alwaysVisible="true">
<button id="customersGridCreateBtn" action="customersGrid.create"/>
<button id="customersGridEditBtn" action="customersGrid.edit"/>
<button id="customersGridRemoveBtn" action="customersGrid.remove"/>
</buttonsPanel>
<simplePagination/>
<columns>
<column id="hobby" property="hobby"/>
<column id="firstName" property="firstName"/>
<column id="lastName" property="lastName"/>
<column id="age" property="age"/>
<column id="email" property="email"/>
<column id="level" property="level"/>
<column id="rewardPoints" property="rewardPoints"/>
</columns>
</dataGrid>
</layout>
其中,为 Customer
实体使用了 集合数据容器。DataGrid
组件通过 dataContainer
属性与数据容器绑定,columns
元素定义那些实体属性要显示在数据网格的列中。
数据绑定
声明式绑定
通常,使用 dataContainer
属性在界面 XML 描述中将数据与 dataGrid
绑定。此时需要使用一个 集合数据容器。
使用键值对容器
数据网格还可以绑定至 键值对容器 展示查询的纯数值和聚合值。示例:
<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>
<dataGrid id="keyValueGrid" width="100%" dataContainer="salesDc">
<columns>
<column id="customerName" caption="Customer"/>
<column id="sum" caption="Summary amount"/>
</columns>
</dataGrid>
</layout>
编程式绑定
如需以编程的方式在界面控制器定义数据容器,则可以在 XML 中设置 metaClass 属性而非 dataContainer。
<dataGrid id="customersDataGrid"
width="100%"
metaClass="uiex1_Customer">
<columns>
<column id="firstName" property="firstName"/>
<column id="lastName" property="lastName"/>
</columns>
</dataGrid>
界面控制器中,使用 ContainerDataGridItems
类将数据网格和数据容器绑定:
@Autowired
private DataGrid<Customer> customersDataGrid;
@Autowired
private CollectionContainer<Customer> customersDc;
@Subscribe
public void onInit(InitEvent event) {
customersDataGrid.setItems(new ContainerDataGridItems<>(customersDc));
}
columns 元素
数据网格的列集合定义在 columns
元素中。如果未指定,则通过 dataContainer
定义的 fetch plan 自动确定。
columns
元素有如下属性:
-
includeAll
加载dataContainer
中定义的fetchPlan
的所有属性。在下面的例子中,我们显示了
customersDc
中使用 fetch plan 的所有属性:<dataGrid id="gridIncludeAll" width="100%" dataContainer="customersDc"> <columns includeAll="true"/> </dataGrid>
如果实体的 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> <dataGrid id="gridIncludeAllReference" width="100%" dataContainer="customersDc1"> <columns includeAll="true"> <column id="city.country.name"/> </columns> </dataGrid> </layout>
-
exclude
英文逗号分隔的属性列表,这些属性不会被加载到数据网格。在下面的例子中,我们会显示除了
id
、maritalStatus
和email
之外的所有属性:<dataGrid id="gridExclude" width="100%" dataContainer="customersDc"> <columns includeAll="true" exclude="id,maritalStatus,email"/> </dataGrid>
column 元素
每一列是在内部的 column
元素中描述。
id
- 非必需属性,指定列标识。如果没有设置,对应的 property
值会被用作该列的标识。如果 id
和 property
都不设置,会抛出 GuiDevelopmentException
异常。对于 代码生成列,则 id
属性是必需的。
property
- 指定列对应的实体属性。可以是数据容器实体的属性,也可以是关联实体的属性,关联实体属性前面需要加上关联类名字并通过“.”连接。例如:
<columns>
<column property="firstName"/>
<column property="lastName"/>
<column property="city.name"/>
<column property="city.country.name"/>
</columns>
如需在 Jmix Studio 中添加 |
列标题
隐藏列开关中也使用这个标题展示列名,除非在 collapsingToggleCaption 属性单独设置。
列折叠
collapsed
- 可选属性,设置为 true
时自动隐藏该列。collapsed
属性默认值为 false
。用户可以通过数据网格右上角的 按钮提供的菜单控制列的可见性,此时需要设置 columnsCollapsingAllowed 为 true
。
collapsible
定义用户是否可以通过 DataGrid
表格组件的列控制按钮隐藏/显示该列。默认为 true
。
<dataGrid id="collapsedGrid"
width="100%"
dataContainer="customersDc">
<columns>
<column property="firstName"
collapsible="false"/>
<column property="lastName"
collapsible="false"/>
<column property="age"
collapsed="true"/>
<column property="hobby"
collapsingToggleCaption="The favourite customer's hobby"/>
<column property="level"/>
<column property="city"/>
</columns>
</dataGrid>
可以看到,age
列默认是折叠不显示的,但是用户可以通过 按钮的下拉菜单显示它。
另外,firstName
和 lastName
列是不能隐藏的。
列控制按钮的下拉项中,展示了 hobby
列的自定义标题。
列折叠可以通过事件 ColumnCollapsingChangeEvent 进行跟踪。
列宽度
width
- 可选属性,定义列宽。只支持以像素为单位的数值类型。
<columns>
<column property="firstName" width="120"/>
<column property="lastName" width="150"/>
<column property="city" width="100"/>
</columns>
expandRatio
- 可选属性,设置列宽占比。比值必须大于等于 0。如果至少有一列设置了其他值,则忽略所有的隐式值,并且只使用设置的值。
默认情况下,所有列等宽(expandRatio = 1
)。
如果同时设置了 width
和 expandRatio
属性,则 expandRatio
会被忽略。
<columns>
<column property="firstName" expandRatio="0"/>
<column property="lastName" expandRatio="1"/>
<column property="city" expandRatio="2"/>
</columns>
上面的例子中,DataGrid
组件有三列,列宽占比分别为 0
、1
和 2
。占比为 0
的列宽与内容所需的宽度一致。占比为 1
的列宽除了展示内容所需的宽度之外,还占用了剩余宽度的 1/3。占比为 2
的列宽除了展示内容所需的宽度之外,还占用了剩余宽度的 2/3。
如需清除占比值,可以为 expandRatio
属性设置一个负值。
minimumWidth
定义占比时列可占用的最小列宽,以像素为单位。
maximumWidth
定义占比时列可占用的最大列宽,以像素为单位。
调整列宽
用户可以调整列宽:
resizable
属性定义用户是否可以调整此列。默认所有列都可手动调整。
用 columnResizeMode
设置调整列宽时的动画效果。支持两种效果:
-
ANIMATED
,动画效果,列宽跟随鼠标拖拽(默认)。 -
SIMPLE
,简单效果,列宽会在拖拽动作结束后才发生改变。
列宽变化事件可以通过 ColumnResizeEvent 跟踪。
列重排
DataGrid
提供拖拽功能,用户可以改变数据网格内列的展示顺序。
列重排的功能是默认开启的。如需禁用,可设置 reorderingAllowed
属性为 false
。
列顺序改变可用 ColumnReorderEvent 跟踪。
列锁定
DataGrid
支持将列固定在左侧。在查看有很多列的数据时,重要的列可以固定在左边总是可见。固定的列不会随着水平滚动条移动。
设置固定列的个数。0
表示不需要固定任何列,除了使用 复选框选择模式 开启多选时的预定义复选框列。设为 -1
的时候即使选择列也不固定。默认值为 0
。
下面的示例是左侧固定两列的数据网格。
<dataGrid id="frozenGrid"
width="100%" footerVisible="false"
dataContainer="customersDc"
frozenColumnCount="2">
<columns>
<column property="firstName"/>
<column property="lastName"/>
<column property="age"/>
<column property="email"/>
<column property="level"/>
<column property="rewardPoints"/>
<column property="hobby"/>
<column property="city"/>
</columns>
</dataGrid>
尺寸
列尺寸
参阅 列宽度 章节的 width
、expandRatio
、minimumWidth
和 maximumWidth
属性。
行尺寸
用 headerRowHeight 属性设置 header 高度。
用 bodyRowHeight
属性设置数据行高度(单位像素)。如果值为 -1
,会在 DataGrid
显示前基于主题中空行的高度计算数据行的高度。
用 footerRowHeight 属性设置 footer 高度。
下面示例中,DataGrid
组件有自定义的表头和数据行高度:
<dataGrid id="sizedGrid"
width="100%"
dataContainer="customersDc"
headerRowHeight="36"
bodyRowHeight="28">
<columns>
<column id="firstName" property="firstName"/>
<column id="lastName" property="lastName"/>
<column id="level" property="level"/>
<column id="age" property="age"/>
<column id="rewardPoints" property="rewardPoints"/>
</columns>
</dataGrid>
选择
DataGrid
组件支持对数据行进行单选和多选。
selectionMode
属性设置行选择模式。有四种预定义的模式:
-
SINGLE
- 单选; -
MULTI
- 多选; -
MULTI_CHECK
- 复选框多选; -
NONE
- 不可选择。
行选择事件可以用 SelectionEvent 跟踪。
空状态
在数据容器没有数据或者没有设置数据容器时,支持为 DataGrid
设置展示空状态消息或链接。
空状态消息通过 emptyStateMessage
属性定义。可以用于显示无数据的原因。
空状态链接通过 emptyStateLinkMessage
属性定义。可以显示加载数据需要进行的操作。
示例:
<dataGrid id="placeholderGrid"
width="100%"
height="200"
metaClass="uiex1_Customer"
emptyStateMessage="No customers added."
emptyStateLinkMessage="Add customer">
<columns>
<column id="firstName" property="firstName"/>
<column id="lastName" property="lastName"/>
<column id="level" property="level"/>
<column id="age" property="age"/>
<column id="rewardPoints" property="rewardPoints"/>
</columns>
</dataGrid>
emptyStateMessage
和 emptyStateLinkMessage
属性都可以从 消息包 中加载本地化消息。
用 EmptyStateLinkClickHandler 处理空状态链接的点击。
列可见控制
用户可以用数据网格 header 右侧的 列控制按钮选择 折叠 隐藏哪些列。
当前展示列在下拉列表中是勾选状态。其他的菜单项:
-
Select all
- 展示所有的数据网格列。 -
Deselect all
- 隐藏所有能隐藏的列。
如果 columnsCollapsingAllowed
属性设置为 false
,则用户不能折叠列。默认值是 true
。
Headers 和 Footers
headerVisible
属性定义是否显示 DataGrid
header。默认值是 true
。
使用 headerRowHeight
属性设置 header 的行高(单位是像素)。如果值设置为 -1
,则在 DataGrid
展示之前根据主题中空行的高度计算行高。默认值是 -1
。
HeaderRow
和 FooterRow
接口分别用来展示 header 和 footer 单元格。这些单元格可以是合并列。
DataGrid
的下列方法支持创建和管理 DataGrid
的 header 和 footer:
-
appendHeaderRow()
、appendFooterRow()
- 在 header/footer 底部添加新行。 -
prependHeaderRow()
、prependFooterRow()
- 在 header/footer 顶部添加新行。 -
addHeaderRowAt()
、addFooterRowAt()
- 在 header/footer 中的指定位置添加新行。当前行和后面已经存在的行依次下移且索引值相应增加。 -
removeHeaderRow()
、removeFooterRow()
- 从 header/footer 删除指定的行。 -
getHeaderRowCount()
、getFooterRowCount()
- 获取 header/footer 的行数。 -
setDefaultHeaderRow()
- 设置 header 的默认行。默认行是一个特殊的 header,提供列排序的功能。
HeaderCell
和 FooterCell
接口提供自定义静态单元格功能:
-
setStyleName()
- 为单元格设置自定义样式名称。 -
getCellType()
- 返回单元格内容类型。静态单元格枚举类型DataGridStaticCellType
有三个值:-
TEXT
-
HTML
-
COMPONENT
-
-
getComponent()
、getHtml()
、getText()
- 不同类型单元格获取内容的方法。
下面这个例子中,header 包含合并的单元格,footer 显示经计算得出的值。
<dataGrid id="dataGrid"
width="100%"
footerRowHeight="140"
headerRowHeight="40"
dataContainer="customersDc">
<columns>
<column property="firstName"/>
<column property="lastName"/>
<column property="age"/>
<column property="level"/>
<column property="rewardPoints"/>
</columns>
</dataGrid>
@Autowired
private DataGrid<Customer> dataGrid;
@Autowired
private CollectionLoader<Customer> customersDl;
private int silverCount = 0;
private int goldCount = 0;
private int platinumCount = 0;
private int diamondCount = 0;
@Subscribe
public void onInit(InitEvent event) {
customersDl.load();
initFooter();
initHeader();
}
private void initFooter() {
DataGrid.FooterRow footerRow = dataGrid.prependFooterRow();
DataGrid.FooterCell footerCell = footerRow.join("firstName","lastName");
footerCell.setHtml("<strong>Total customers count: " +
customersDc.getItems().size() + "</strong>");
calculateMemberCount();
footerRow.getCell("age").setHtml("<strong>Average age: " + getAverage("age") +
"</strong>");
footerRow.getCell("level").setHtml("<strong>Silver Members: " + silverCount +
"<br>" + "Gold Members: " + goldCount + "<br>" +
"Platinum Members: " + platinumCount + "<br>" +
"Diamond Members: " + diamondCount + "<br>" +
"</strong>");
footerRow.getCell("rewardPoints").setHtml("<strong>Average reward points: " +
getAverage("rewardPoints") + "</strong>");
}
private void initHeader() {
DataGrid.HeaderRow headerRow = dataGrid.prependHeaderRow();
DataGrid.HeaderCell headerCell = headerRow.join("firstName", "lastName");
headerCell.setText("Full name");
headerCell.setStyleName("center-bold");
headerCell = headerRow.join("level", "rewardPoints");
headerCell.setText("Account information");
headerCell.setStyleName("center-bold");
}
private int getAverage(String propertyId) {
double average = 0.0;
Collection<Customer> items = customersDc.getItems();
for (Customer customer : items) {
Double value = propertyId.equals("rewardPoints") ?
customer.getRewardPoints().doubleValue() :
customer.getAge().doubleValue();
average += value != null ? value : 0.0;
}
return (int) (average / items.size());
}
private void calculateMemberCount() {
Collection<Customer> items = customersDc.getItems();
for (Customer customer : items) {
switch (customer.getLevel()) {
case SILVER:
silverCount++;
break;
case GOLD:
goldCount++;
break;
case PLATINUM:
platinumCount++;
break;
case DIAMOND:
diamondCount++;
break;
}
}
}
聚合
DataGrid
支持对行内值进行聚合运算。
支持下列运算符:
-
SUM
- 求和 -
AVG
- 求平均值 -
COUNT
- 计数 -
MIN
- 最小值 -
MAX
- 最大值
如需启用对 DataGrid
的行进行聚合运算,按照下列配置:
-
设置
aggregatable
属性值为true
。 -
为聚合列设置
aggregation
元素。 -
设置
aggregation
元素的type
属性,表示聚合的函数。
如需在 Jmix Studio 中定义 |
聚合值展示在附加行中。
aggregationPosition
属性可以设置聚合值行的位置:TOP
或 BOTTOM
。默认为 TOP
。
默认情况下,聚合列只支持数字类型,比如 |
带聚合列的 DataGrid
XML 描述示例:
<dataGrid id="aggregationGrid"
width="100%"
dataContainer="customersDc1"
aggregatable="true">
<columns>
<column id="firstName" property="firstName"/>
<column id="lastName" property="lastName"/>
<column id="level" property="level"/>
<column id="age" property="age">
<aggregation type="AVG"/>
</column>
<column id="rewardPoints" property="rewardPoints"/>
</columns>
</dataGrid>
valueDescription
属性定义一个提示,当用户的光标悬停在聚合值上时通过弹出框展示这个提示。对于上面列出的运算(SUM
、AVG
、COUNT
、MIN
、MAX
),提示弹窗已经默认开启。
可以指定不同于 Datatype
标准格式的 formatter 显示聚合值:
<column id="amount" property="amount">
<aggregation type="SUM">
<formatter>
<number format="#,##0.00"/>
</formatter>
</aggregation>
</column>
aggregation
元素还可以包含 strategyClass
属性,指定一个实现 AggregationStrategy
接口的类。
public class CustomerHobbyAggregation 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;
}
}
<dataGrid id="gridAggregationStrategy"
width="100%"
aggregatable="true"
dataContainer="customersDc">
<columns>
<column id="firstName" property="firstName"/>
<column id="lastName" property="lastName"/>
<column id="hobby" property="hobby">
<aggregation
strategyClass="ui.ex1.screen.component.datagrid.CustomerHobbyAggregation"/>
</column>
</columns>
</dataGrid>
排序
DataGrid
支持对列数据进行排序。排序功能默认开启。
sortable
属性可以启用数据网格的排序功能。默认为 true
。开启后,点击列名会在列名右边显示 / 图标。
按住 Shift
的同时选择多列可以按多列排序。
使用特定 列 的 sortable
属性可以禁用该列的排序功能。
下面的例子中,我们禁用了 lastName
列的排序:
<columns>
<column id="firstName" property="firstName"/>
<column id="lastName" property="lastName" sortable="false"/>
<column id="city" property="city"/>
<column id="hobby" property="hobby"/>
</columns>
column
元素的 sort
属性可以设置该列的初始排序。值选项:
-
ASCENDING
- 顺序(0 → 9 → A → Z)。 -
DESCENDING
- 倒序(Z → A → 9 → 0)。
示例:
<columns>
<column id="firstName" property="firstName" sort="DESCENDING"/>
<column id="lastName" property="lastName"/>
<column id="city" property="city"/>
<column id="hobby" property="hobby"/>
</columns>
|
DataGrid
排序事件可以用 SortEvent 跟踪。
分页
dataGrid
可以使用 SimplePagination 简单分页器 组件来提供分页功能:
<dataGrid id="gridPagination"
width="100%"
dataContainer="customersDc">
<columns>
<column id="firstName" property="firstName"/>
<column id="lastName" property="lastName"/>
<column id="hobby" property="hobby"/>
<column id="age" property="age"/>
</columns>
<simplePagination
itemsPerPageVisible="true"
itemsPerPageOptions="2, 4, 6"/>
</dataGrid>
或者,可以使用独立的 Pagination 分页 组件。
DataGrid 操作
DataGrid
组件实现了 ActionsHolder
接口,可以包含自定义操作和 标准列表操作。
数据网格的操作定义在内部的 actions
元素中。
如需在 Jmix Studio 中添加 |
如果操作有标题,则会显示在数据网格的 右键菜单 中。此外,数据网格的操作可以分配给界面中任意位置的按钮。
<dataGrid id="gridWithActions"
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" property="age"/>
<column id="firstName" property="firstName"/>
<column id="lastName" property="lastName"/>
</columns>
<buttonsPanel id="buttonsActionsPanel" alwaysVisible="true"> (3)
<button id="create" action="gridWithActions.create"/>
<button id="edit" action="gridWithActions.edit"/>
<button id="remove" action="gridWithActions.remove"/>
<button id="about" action="gridWithActions.about"/>
</buttonsPanel>
</dataGrid>
1 | 定义 create 标准操作。 |
2 | 定义 about 自定义操作。 |
3 | 在数据网格内定义 ButtonsPanel 容器。 |
列生成
通过 ColumnGeneratorEvent
事件的处理器可以添加动态生成或者动态计算的列,并提供自定义的数据展示。
在渲染数据网格时,事件处理器由框架对每个单元格进行调用。ColumnGeneratorEvent
包含当前行展示的实体信息以及列标识符。
可以用 Studio 创建 ColumnGeneratorEvent
事件的处理器。需选择 Studio 建议的生成类型和对应的 渲染器 类型。
示例,我们生成一个包含 customer 全名称的列。
首先,创建一个 id 为 fullName
的列:
<column id="fullName" caption="Full name">
<textRenderer nullRepresentation="null"/>
</column>
然后用 Studio 为 fullName
列创建 ColumnGeneratorEvent
处理器并实现如下:
@Install(to = "grid.fullName", subject = "columnGenerator")
private String gridFullNameColumnGenerator(DataGrid.ColumnGeneratorEvent<Customer> columnGeneratorEvent) {
return columnGeneratorEvent.getItem().getFirstName() + " " + columnGeneratorEvent.getItem().getLastName();
}
结果:
fullName
列是一个使用 TextRenderer 的生成列。
如需编程式注册列生成处理器,使用 DataGrid
组件的 addGeneratedColumn()
方法。
列值导出
使用 表格导出 扩展组件可以将 DataGrid
组件的内容导出成支持的文件类型。
安装完组件后,可以为数据网格定义 excelExport 或 jsonExport 操作,也可使用 表格导出器。
下面的例子中,在使用 excelExport
操作导出 XLSX 文件时,为数据的某一列设置了自定义的输出。
界面描述:
<dataGrid id="gridExport"
width="100%"
dataContainer="customersDc">
<actions>
<action id="excelExport" type="excelExport"/>
</actions>
<columns>
<column id="firstName" property="firstName"/>
<column id="hobby" property="hobby"/>
<column id="age" property="age"/>
</columns>
</dataGrid>
界面控制器:
@Named("gridExport.excelExport")
protected ExcelExportAction gridExcelExport;
@Subscribe
public void onInit(InitEvent event) {
gridExcelExport.addColumnValueProvider("firstName", context -> { (1)
Customer customer = context.getEntity();
return "Name: " + customer.getFirstName();
});
}
1 | 该方法一个参数是列标识符,第二个是从列中获取展示值的函数。 |
渲染器
数据在列中的显示方式可以使用带参数的渲染器(renderer)以声明式的方法自定义。一些 DataGrid
的渲染器通过特定的 XML 元素设置,并且定义了对应的属性作为参数。对常规列和生成列,都可以声明渲染器。
框架提供下列渲染器:
ButtonRenderer
ButtonRenderer
渲染为按钮,按钮标题为字符串。
ButtonRenderer
不能在 XML 描述中定义,因为没有办法在 XML 描述中定义渲染器点击监听器。Studio 会在界面控制器的 onInit()
中生成 ButtonRenderer
的声明代码,示例:
@Autowired
private Notifications notifications;
@Autowired
private DataGrid<Customer> gridButtonRenderer;
@Subscribe
public void onInit(InitEvent event) {
DataGrid.ButtonRenderer<Customer> gridButtonRendererFirstNameRenderer =
getApplicationContext().getBean(DataGrid.ButtonRenderer.class);
gridButtonRendererFirstNameRenderer.setRendererClickListener(
clickableRendererClickEvent ->
notifications.create()
.withCaption("ButtonRenderer")
.withDescription("Column id: " +
clickableRendererClickEvent.getColumnId())
.show());
gridButtonRenderer.getColumn("firstName")
.setRenderer(gridButtonRendererFirstNameRenderer);
}
ImageRenderer
-
ImageRenderer
是一个展示图片的渲染器。对应属性的值用作图片地址,地址可以是主题资源或 URL。
ImageRenderer
不能在 XML 描述中定义,因为没有办法在 XML 描述中定义渲染器点击监听器。Studio 会在界面控制器的 onInit()
中生成 ImageRenderer
的声明代码,示例:
@Autowired
private Notifications notifications;
@Autowired
private DataGrid<Country> imageGrid;
@Subscribe
public void onInit(InitEvent event) {
DataGrid.ImageRenderer<Country> imageGridFlagRenderer =
getApplicationContext().getBean(DataGrid.ImageRenderer.class);
imageGridFlagRenderer.setRendererClickListener(clickableTextRendererClickEvent -> {
});
imageGrid.getColumn("flag").setRenderer(imageGridFlagRenderer);
}
结果:
CheckBoxRenderer
CheckBoxRenderer
将布尔值作为复选框展示。
DataGrid
的 column
元素有一个子元素 checkBoxRenderer
:
<column id="isEmail" caption="Is email">
<checkBoxRenderer/>
</column>
NumberRenderer
NumberRenderer
按照定义的格式展示数字。
DataGrid
的 column
元素有一个子元素 numberRenderer
,numberRenderer
有可选属性 nullRepresentation
和必需字符串属性 format
。
<column id="percent" property="percent">
<numberRenderer nullRepresentation="null" format="%d%%"/>
</column>
formatString
是描述数字格式的字符串,用来创建 NumberFormat
实例。
LocalDateTimeRenderer
LocalDateTimeRenderer
以 LocalDateTime
值展示日期时间。
DataGrid
的 column
元素有子元素 localDateTimeRenderer
,该元素有非必要的 nullRepresentation
属性和必填的 format
字符串属性:
<column id="dateTime" property="dateTime">
<localDateTimeRenderer nullRepresentation="null"
format="dd/MM/YYYY HH:mm:ss"/>
</column>
LocalDateRenderer
LocalDateRenderer
以 LocalDate
值显示日期。
DataGrid
的 column
元素有子元素 localDateRenderer
,该元素有非必要的 nullRepresentation
属性和必填的 format
字符串属性:
<column id="date" property="date">
<localDateRenderer nullRepresentation="null" format="dd/MM/YYYY"/>
</column>
结果:
DateRenderer
DateRenderer
用定义的格式显示日期。
DataGrid
的 column
元素有子元素 dateRenderer
,该元素有非必要的 nullRepresentation
属性和必填的 format
字符串属性:
<dataGrid id="eventGrid"
width="100%"
dataContainer="eventsDc">
<columns>
<column id="name" property="name"/>
<column id="startDate" property="startDate">
<dateRenderer nullRepresentation="null"
format="yyyy-MM-dd HH:mm:ss"/>
</column>
<column id="endDate" property="endDate"/>
</columns>
</dataGrid>
formatString
是描述日期时间格式的字符串,用来创建 DateFormat
实例。
注意这里 startDate
字段有 DateRenderer
,而 endDate
没有。
ProgressBarRenderer
ProgressBarRenderer
将 0~1 之间 double
类型的值展示为 ProgressBar
组件。
DataGrid
的 column
元素有子元素 progressBarRenderer
:
<column id="percent" property="percent">
<progressBarRenderer/>
</column>
结果:
HtmlRenderer
HtmlRenderer
展示 HTML。
DataGrid
的 column
元素有子元素 htmlRenderer
,该元素有非必要的属性 nullRepresentation
。
下面是渲染 endDate
属性的示例:
<column id="endDate" property="endDate">
<htmlRenderer nullRepresentation="null"/>
</column>
@Install(to = "htmlGrid.endDate", subject = "columnGenerator")
private String htmlGridEndDateColumnGenerator(DataGrid.ColumnGeneratorEvent<Event> columnGeneratorEvent) {
return columnGeneratorEvent.getItem().getEndDate().before(new Date())
? "<font color='red'>" +
columnGeneratorEvent.getItem().getEndDate() + "</font>"
: "<font color='green'>" +
columnGeneratorEvent.getItem().getEndDate() + "</font>";
}
结果:
ClickableTextRenderer
ClickableTextRenderer
将普通的文本字符串显示为链接,并有点击事件处理器。
ClickableTextRenderer
不能在 XML 描述中定义,因为没有办法在 XML 描述中定义渲染器点击监听器。Studio 会在界面控制器的 onInit()
中生成 ClickableTextRenderer
的声明代码,示例:
@Autowired
private Notifications notifications;
@Autowired
private DataGrid<Customer> gridClick;
@Subscribe
public void onInit(InitEvent event) {
DataGrid.ClickableTextRenderer<Customer> gridClickFirstNameRenderer =
getApplicationContext().getBean(DataGrid.ClickableTextRenderer.class);
gridClickFirstNameRenderer.setRendererClickListener(clickEvent ->
notifications.create()
.withDescription("The full name: " +
clickEvent.getItem().getFirstName() +
" " + clickEvent.getItem().getLastName())
.show());
gridClick.getColumn("firstName").setRenderer(gridClickFirstNameRenderer);
}
结果:
TextRenderer
TextRenderer
展示简单的字符串。
DataGrid
的 column
元素有子元素 textRenderer
,该元素有非必要的 nullRepresentation
属性:
<column id="fullName" caption="Full name">
<textRenderer nullRepresentation="null"/>
</column>
ComponentRenderer
ComponentRenderer
UI 组件渲染器。
DataGrid
的 column
元素有子元素 componentRenderer
:
<column id="age" property="age">
<componentRenderer/>
</column>
下面的例子中,我们用 Slider
组件展示 age
的值。
@Install(to = "gridComponent.age", subject = "columnGenerator")
private Component gridComponentAgeColumnGenerator(DataGrid.ColumnGeneratorEvent<Customer> columnGeneratorEvent) {
Slider<Integer> slider = uiComponents.create(Slider.NAME);
slider.setValue(columnGeneratorEvent.getItem().getAge());
slider.setEditable(false);
slider.setWidth("150px");
return slider;
}
结果:
IconRenderer
IconRenderer
展示 JmixIcon
的渲染器。
DataGrid
的 column
元素有子元素 iconRenderer
。
下面示例,渲染生成的 hasEmail
属性:
<column id="hasEmail" caption="Has id">
<iconRenderer/>
</column>
@Install(to = "iconGrid.hasEmail", subject = "columnGenerator")
private Icons.Icon iconGridHasEmailColumnGenerator(DataGrid.ColumnGeneratorEvent<Customer> columnGeneratorEvent) {
return columnGeneratorEvent.getItem().getEmail() != null ?
JmixIcon.OK : JmixIcon.EXCLAMATION_TRIANGLE;
}
结果:
数据详情生成器
数据详情是在可展开的区域展示特定行的更多信息。
DetailsGenerator
接口支持创建自定义组件展示数据详情。
用 Studio 可以为 DataGrid
创建 DetailsGenerator` 处理器(参阅 处理器)并实现:
@Autowired
private DataGrid<Customer> detailsGrid;
@Install(to = "detailsGrid", subject = "detailsGenerator")
private Component detailsGridDetailsGenerator(Customer customer) {
VBoxLayout mainLayout = uiComponents.create(VBoxLayout.class);
mainLayout.setWidth("100%");
mainLayout.setMargin(true);
HBoxLayout headerBox = uiComponents.create(HBoxLayout.class);
headerBox.setWidth("100%");
Label<String> infoLabel = uiComponents.create(Label.TYPE_STRING);
infoLabel.setHtmlEnabled(true);
infoLabel.setStyleName("h1");
infoLabel.setValue("Customer info:");
Component closeButton = createCloseButton(customer);
headerBox.add(infoLabel);
headerBox.add(closeButton);
headerBox.expand(infoLabel);
Component content = getContent(customer);
mainLayout.add(headerBox);
mainLayout.add(content);
mainLayout.expand(content);
return mainLayout;
}
protected Component createCloseButton(Customer entity) {
Button closeButton = uiComponents.create(Button.class);
closeButton.setIcon("font-icon:TIMES");
BaseAction closeAction = new BaseAction("closeAction")
.withHandler(actionPerformedEvent ->
detailsGrid.setDetailsVisible(entity, false))
.withCaption("");
closeButton.setAction(closeAction);
return closeButton;
}
protected Component getContent(Customer entity) {
Label<String> content = uiComponents.create(Label.TYPE_STRING);
content.setHtmlEnabled(true);
content.setId("contentLabel");
StringBuilder sb = new StringBuilder();
sb.append("<b>Full name</b><br>")
.append(entity.getFirstName() + " " + entity.getLastName() + "<br><br>")
.append("<b>Country</b><br>")
.append(entity.getCity().getCountry().getName()+ "<br><br>")
.append("<b>City</b><br>")
.append(entity.getCity().getName());
content.setValue(sb.toString());
return content;
}
如需手动处理显示和隐藏,需要自己实现监听器。下面的例子中,我们在 DataGrid
组件的 ItemClickAction
中打开详情:
@Subscribe("detailsGrid")
public void onDetailsGridItemClick(DataGrid.ItemClickEvent<Customer> event) {
detailsGrid.setItemClickAction(new BaseAction("itemClickAction")
.withHandler(actionPerformedEvent ->
detailsGrid.setDetailsVisible(detailsGrid.getSingleSelected(), true)));
}
结果:
编辑
DataGrid
组件支持行内编辑器来编辑单元格数据。设置 editorEnabled
属性为 true
启用行内编辑。
使用方法
-
双击需要编辑的字段或选中可编辑单元格后按下回车都可以开启行内编辑。
-
带有
editable = true
属性的列展示实体属性编辑的组件。不可编辑字段则无法使用。 -
每个可编辑列的编辑组件是根据对应实体的属性自动选取的。例如,对于字符串和数字类型的属性,使用 TextField,日期时间 - DateField,枚举 - ComboBox,实体引用 - EntityPicker。
-
当一行处于编辑模式时,会显示默认的 OK 和 Cancel 按钮,用户可提交或取消编辑。
-
如需保存修改并退出编辑模式,点击 OK 按钮或按回车。
-
如需放弃修改并退出编辑模式,点击 Cancel 按钮或按 Esc。
模式
编辑模式分为缓存模式和非缓存模式。
-
缓存模式编辑,数据的修改必须显式提交。
-
非缓存模式编辑,当字段失去焦点时自动提交。
editorBuffered
属性用于设置缓存编辑模式。默认为 true
。
此时,数据的修改只是提交至数据容器。数据保存至数据库的过程通常在界面提交时由 数据上下文 完成。
自定义行内编辑器
可以通过 EditorFieldGenerationContext
类对编辑器组件进行定制。
在 DataGrid
编辑模式中创建一个编辑字段生成器,用于为该列生成编辑组件,示例:
@Autowired
private CollectionContainer<City> citiesDc;
@Install(to = "editingGrid.city", subject = "editFieldGenerator")
private Field<City> editingGridCityEditFieldGenerator(
DataGrid.EditorFieldGenerationContext<Customer> editorFieldGenerationContext) {
ComboBox<City> comboBox = uiComponents.create(ComboBox.NAME);
comboBox.setValueSource((ValueSource<City>) editorFieldGenerationContext
.getValueSourceProvider().getValueSource("city"));
comboBox.setOptionsList(citiesDc.getItems());
return comboBox;
}
结果:
还有通过声明式的方式定义使用何种组件选择实体的通用机制。基于 jmix.ui.component.entity-field-type 和 jmix.ui.component.entity-field-actions 属性。
例如,可以在 application.properties
文件中增加下面的内容:
jmix.ui.component.entity-field-type.uiex1_City = entityComboBox
jmix.ui.component.entity-field-actions.uiex1_City = entity_lookup, entity_open, entity_clear
然后,会自动为 City
实体生成 EntityComboBox
组件:
跨字段验证
DataGrid
的行内编辑器也可以考虑实体约束(跨字段验证)。如果有验证错误,DataGrid
会展示错误消息。用 editorCrossFieldValidate
属性启用/禁用验证。默认值为 true
。
编辑器事件
编辑器事件提供对其使用组件的访问,支持修改或使用组件值。
-
EditorOpenEvent
在DataGrid
编辑器打开之前发送的事件。示例:
@Subscribe("editEventsGrid") public void onEditEventsGridEditorOpen(DataGrid.EditorOpenEvent<Event> event) { Map<String, Field> fields = event.getFields(); Field field1 = fields.get("startDate"); Field field2 = fields.get("endDate"); field1.addValueChangeListener(valueChangeEvent -> field2.setValue(DateUtils.addDays((Date) field1.getValue(), 1))); field2.addValueChangeListener(valueChangeEvent -> field1.setValue(DateUtils.addDays((Date) field2.getValue(), -1))); }
-
EditorCloseEvent
在DataGrid
编辑器关闭之后发送的事件。
-
EditorPreCommitEvent
在数据更新之前发送的事件。
-
EditorPostCommitEvent
在数据更新之后发送的事件。
右键菜单
在数据网格中点击右键可以激活右键菜单。
contextMenuEnabled
属性可以开启右键菜单。默认值为 true
。右键菜单展示 数据网格操作(如果有的话)。
右键点击的事件可以通过 ContextClickEvent 跟踪。
样式
可以在界面 XML 或者控制器中使用 stylename
属性为 DataGrid
组件设置预定义样式:
<dataGrid id="progressGrid"
width="100%"
stylename="no-stripes"
dataContainer="budgetItemsDc">
progressGrid.setStyleName(ThemeClassNames.DATAGRID_NO_STRIPES);
预定义样式:
-
borderless
- 删除数据网格外边框; -
no-horizontal-lines
- 删除行之间的水平分隔线; -
no-vertical-lines
- 删除列之间的垂直分隔线; -
no-stripes
- 删除行间隔背景色。
DataGrid
的外观可以使用带 $jmix-datagrid-*
前缀的 SCSS 变量进行自定义。在创建了 自定义主题 之后,可以在可视化编辑器中修改这些变量。
也可以参阅 RowStyleProvider。
DataGrid 接口方法
-
getColumns()
按当前界面的展示顺序获取列集合。
-
getVisibleColumns()
获取有权限查看的所有列集合。
-
sort()
方法对DataGrid
的数据按照所选择的列和排序规则进行 排序。
-
scrollTo()
将DataGrid
滚动到指定行。需要一个实体实例作为输入参数来指定滚动到哪一行。除了实体实例参数,另有重载方法支持ScrollDestination
参数,该参数可以为以下值:-
ANY
- 滚动尽量少的位置来展示所目标元素。如果元素在视图内,则根据当前滚动条的位置,此配置与START
或END
相同。如果元素不在视图内,则与START
相同。 -
START
- 使所需要的数据展示在可见部分的顶端。当前视图不会滚动超过所见内容的距离。 -
MIDDLE
- 使所需要的数据展示在可见部分的中部。当前视图不会滚动超过所见内容的距离,即使数据比当前视图能展示的范围还要大。且视图不会滚动超过第一个元素。 -
END
- 使所需要的数据展示在可见部分的底部。视图不会滚动超过第一个元素。
-
-
scrollToStart()
和scrollToEnd()
- 分别滚动DataGrid
至第一个和最后一个数据项。
-
The
getAggregationResults()
方法返回 聚合 结果的 map,key 为DataGrid
的列标识符,value 为聚合值。
事件和处理器
如需使用 Jmix Studio 生成处理器的桩代码,需要在界面 XML 描述或者 Jmix UI 层级结构面板选中该组件,然后用 Jmix UI 组件面板的 Handlers 标签页生成。 或者可以使用界面控制器顶部面板的 Generate Handler 按钮。 |
ColumnCollapsingChangeEvent
ColumnCollapsingChangeEvent
当列的 折叠 状态发生改变时发送。
下面示例为 XML 中 id 是 collapseGrid
的数据网格订阅了该事件:
@Subscribe("collapseGrid")
public void onCollapseGridColumnCollapsingChange(DataGrid.ColumnCollapsingChangeEvent event) {
notifications.create()
.withCaption((event.isCollapsed() ? "Collapsed: " : "Expanded: ") +
event.getColumn().getCaption())
.show();
}
如需以编程的方式注册事件处理器,使用组件的 addColumnCollapsingChangeListener()
方法。
ColumnResizeEvent
ColumnResizeEvent
当列发生 大小改变 时发送。
下面示例为 XML 中 id 是 resizedEventGrid
的数据网格订阅了该事件:
@Subscribe("resizedEventGrid")
public void onResizedEventGridColumnResize(DataGrid.ColumnResizeEvent event) {
notifications.create()
.withCaption("The " + event.getColumn().getCaption() + " column was resized")
.show();
}
如需以编程的方式注册事件处理器,使用组件的 addColumnResizeListener()
方法。
ContextClickEvent
ContextClickEvent
当在 DataGrid
内点击鼠标右键时发送。
ContextClickEvent
包含鼠标事件的详细信息。
下面示例为 XML 中 id 是 contextGrid
的数据网格订阅了该事件:
@Subscribe("contextGrid")
public void onContextGridContextClick(DataGrid.ContextClickEvent event) {
notifications.create()
.withCaption("Clicked " + event.getButton().name())
.show();
}
如需以编程的方式注册事件处理器,使用组件的 addContextClickListener()
方法。
EditorCloseEvent
参阅 EditorCloseEvent。
EditorOpenEvent
参阅 EditorOpenEvent。
ItemClickEvent
ItemClickEvent
当用户点击数据网格时发送。ItemClickEvent
包含下列信息:
-
鼠标事件详情;
-
点击行的实体实例;
-
数据项的
id
; -
点击列的
id
。
下面的示例,当用户单击可编辑单元格时,让用户开始 编辑:
@Subscribe("clickGrid")
public void onClickGridItemClick(DataGrid.ItemClickEvent<Event> event) {
clickGrid.edit(event.getItem());
}
如需以编程的方式注册事件处理器,使用组件的 addItemClickListener()
方法。
SelectionEvent
参阅 SelectionEvent。
SortEvent
SortEvent
当数据发生 排序 变化时发送。
下面示例为 XML 中 id 是 sortGrid
的数据网格订阅了该事件:
@Subscribe("sortGrid")
public void onSortGridSort(DataGrid.SortEvent event) {
notifications.create()
.withCaption("The sort order was changed")
.show();
}
如需以编程的方式注册事件处理器,使用组件的 addSortListener()
方法。
DetailsGenerator
参阅 DetailsGenerator。
RowDescriptionProvider
RowDescriptionProvider
当用户鼠标悬停在 DataGrid
某行时,展示行的描述信息(提示框)。如果为某列也设置了 DescriptionProvider
,那么,由 RowDescriptionProvider
生成的行描述信息只为那些单元格描述 provider 返回 null
的单元格展示。
下面的示例中,我们展示 rowDescGrid
的 RowDescriptionProvider
用法:
@Install(to = "rowDescGrid", subject = "rowDescriptionProvider")
private String rowDescGridRowDescriptionProvider(Customer customer) {
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;
}
结果:
如需以编程的方式注册 provider,使用组件的 setRowDescriptionProvider()
方法。
RowStyleProvider
RowStyleProvider
支持 DataGrid
行级的样式 provider。
DataGrid
可以使用多个 providers 获取行的样式名。
设置样式示例:
@Install(to = "styledGrid", subject = "rowStyleProvider")
private String styledGridRowStyleProvider(Customer customer) {
switch (customer.getLevel()) {
case SILVER:
return "level-silver";
case GOLD:
return "level-gold";
case PLATINUM:
return "level-platinum";
case DIAMOND:
return "level-diamond";
}
return null;
}
然后需要在应用程序主题中定义行样式。创建主题的详细信息请参阅 主题。CSS 选择器中需要使用界面控制器中 provider 返回的样式名。示例:
.v-grid-row.level-silver > td {
background-color: #f2f2f2;
color: black;
}
.v-grid-row.level-gold > td {
background-color: #ffda79;
color: black;
}
.v-grid-row.level-platinum > td {
background-color: #637497;
color: black;
}
.v-grid-row.level-diamond > td {
background-color: #8befff;
color: black;
}
结果:
XML 属性
可以使用 Studio 界面设计器的 Jmix UI 组件面板查看和编辑组件的属性。 |
DataGrid XML 属性
aggregatable - aggregationPosition - align - bodyRowHeight - box.expandRatio - caption - captionAsHtml - colspan - columnResizeMode - columnCollapsingAllowed - contextHelpText - contextHelpTextHtmlEnabled - contextMenuEnabled - css - dataContainer - description - descriptionAsHtml - editorBuffered - editorCancelCaption - editorCrossFieldValidate - editorEnabled - editorSaveCaption - emptyStateLinkMessage - emptyStateMessage - enable - footerRowHeight - footerVisible - frozenColumnCount - headerRowHeight - headerVisible - height - htmlSanitizerEnabled - icon - id - metaClass - minHeight - minWidth - reorderingAllowed - responsive - rowspan - selectionMode - sortable - stylename - tabIndex - textSelectionEnabled - visible - width
Column XML 属性
box.expandRatio - caption - collapsed - collapsible - collapsingToggleCaption - colspan - editable - expandRatio - id - maximumWidth - minimumWidth - property - resizable - rowspan - sort - sortable - width