dataGrid 数据网格
dataGrid
用于展示、排序表格类数据,由于使用了在滚动时加载数据的延迟加载方式,所以此组件具有更好的数据行、列操作性能。
-
XML 元素:
dataGrid
-
Java 类:
DataGrid
基本用法
一个在 XML 视图描述声明 dataGrid
的示例如下:
<data readOnly="true">
<collection id="usersDc"
class="com.company.onboarding.entity.User"> (1)
<fetchPlan extends="_base"/>
<loader id="usersDl">
<query>
<![CDATA[select e from User e order by e.username]]>
</query>
</loader>
</collection>
</data>
<layout>
<dataGrid id="usersTable"
width="100%"
minHeight="20em"
dataContainer="usersDc"> (2)
<columns> (3)
<column property="username"/>
<column property="firstName"/>
<column property="lastName"/>
<column property="active"/>
<column property="onboardingStatus"/>
<column property="joiningDate"/>
</columns>
</dataGrid>
</layout>
1 | User 实体的 集合数据容器。 |
2 | dataGrid 使用 dataContainer 属性绑定 usersDc 数据容器。 |
3 | columns 元素定义在数据网格中展示哪些实体属性。 |

数据绑定
声明式绑定
通常,使用 dataContainer
属性在视图 XML 描述中将数据与 dataGrid
绑定。此时需要使用一个 集合数据容器。
使用键值对容器
数据网格还可以绑定至 键值对容器 展示查询的纯数值和聚合值。示例:
<data readOnly="true">
<keyValueCollection id="statusesDc">
<loader id="statusesLoader">
<query>
<![CDATA[select o.department, o.onboardingStatus,
count(o.onboardingStatus) from
User o group by o.department, o.onboardingStatus]]>
</query>
</loader>
<properties>
<property name="department" datatype="string"/>
<property name="onboardingStatus" datatype="int"/>
<property name="count" datatype="int"/>
</properties>
</keyValueCollection>
</data>
<layout>
<dataGrid width="100%" dataContainer="statusesDc">
<columns>
<column property="department"/>
<column property="onboardingStatus"/>
<column property="count"/>
</columns>
</dataGrid>
</layout>
编程式绑定
如需以编程的方式在视图控制器定义数据容器,则可以在 XML 中设置 metaClass 属性而非 dataContainer。
<dataGrid width="100%" id="dataGrid" metaClass="User">
<columns>
<column property="firstName"/>
<column property="lastName"/>
<column property="username"/>
<column property="joiningDate"/>
<column property="onboardingStatus"/>
</columns>
</dataGrid>
视图控制器中,使用 ContainerDataGridItems
类将数据网格和数据容器绑定:
@ViewComponent
private DataGrid<User> dataGrid;
@ViewComponent
private CollectionContainer<User> usersDc;
@Subscribe
public void onInit(InitEvent event) {
dataGrid.setItems(new ContainerDataGridItems<>(usersDc));
}
columns 元素
数据网格的列集合定义在 columns
元素中。columns
元素有如下属性:
-
includeAll
- 加载数据容器中 fetch plan 的所有属性。在下面的例子中,我们显示了
usersDc
中使用 fetch plan 的所有属性:<dataGrid width="100%" dataContainer="usersDc"> <columns includeAll="true"/> </dataGrid>
如果实体的 fetch plan 包含引用属性,该属性会按照其 实例名 进行展示。如果需要展示一个特定的级联属性,则需要在 fetch plan 和
column
元素中定义:<data readOnly="true"> <collection class="com.company.onboarding.entity.UserStep" id="userStepsDc"> <fetchPlan extends="_base"> <property name="user" fetchPlan="_base"> <property name="department" fetchPlan="_base"/> </property> </fetchPlan> <loader id="userStepsDl"> <query> <![CDATA[select e from UserStep e]]> </query> </loader> </collection> </data> <layout> <dataGrid width="100%" dataContainer="userStepsDc"> <columns includeAll="true"> <column property="user.department.name"/> </columns> </dataGrid> </layout>
-
exclude
- 英文逗号分隔的属性列表,这些属性不会被加载到数据网格。在下面的例子中,我们会显示除了
id
、version
和sortValue
之外的所有属性:<dataGrid width="100%" dataContainer="userStepsDc"> <columns includeAll="true" exclude="id,version,sortValue"/> </dataGrid>
column 元素
每一列是在内部的 column
元素中描述。
如需在 Jmix Studio 中添加 |
property
property
指定列对应的实体属性。可以是数据容器实体的属性,也可以是关联实体的属性,关联实体属性前面需要加上关联类名字并通过 “.” 连接。例如:
<columns>
<column property="user.firstName" sortable="false"/>
<column property="user.lastName" sortable="false"/>
<column property="step" frozen="true" sortable="true"/>
<column property="dueDate" editable="true" sortable="true"/>
<column property="user.department.name" sortable="false"/>
</columns>
操作
dataGrid
组件实现了 HasActions
接口,可以包含自定义操作和标准列表操作。
数据网格的操作定义在内部的 actions
元素中。
如需在 Jmix Studio 中添加 |
可以用 hbox
容器在数据网格上方显示操作按钮。
<hbox id="buttonsPanel" classNames="buttons-panel"> (1)
<button id="createBtn" action="usersDataGrid.create"/>
<button id="editBtn" action="usersDataGrid.edit"/>
<button id="removeBtn" action="usersDataGrid.remove"/>
<button id="infoBtn" action="usersDataGrid.getInfo"/>
</hbox>
<dataGrid width="100%" dataContainer="usersDc" id="usersDataGrid">
<columns>
<column property="username"/>
<column property="firstName"/>
<column property="lastName"/>
<column property="active"/>
<column property="onboardingStatus"/>
<column property="joiningDate"/>
</columns>
<actions>
<action id="create" type="list_create"/> (2)
<action id="edit" type="list_edit"/>
<action id="remove" type="list_remove"/>
<action id="getInfo" text="Get Info"/> (3)
</actions>
</dataGrid>
1 | 在数据网格上方定义一个 buttonsPanel hbox 容器。 |
2 | 定义 list_create 标准操作。 |
3 | 定义 getInfo 自定义操作 |

渲染器
使用 addColumn()
和 addComponentColumn()
方法可以添加列。
为更好地展示数据,可以使用渲染器对添加的列进行配置。
下面示例中,我们创建了一个生成列,并用 LocalDateRenderer
展示用户的入职时间。
@ViewComponent
private DataGrid<User> usersDtGr;
@Subscribe
public void onInit(InitEvent event) {
usersDtGr.addColumn(new LocalDateRenderer<>
(User::getJoiningDate,"dd/MM"))
.setHeader("Joining date");
}
下面的示例中,我们添加一列展示用户的头像:
@ViewComponent
private DataGrid<User> usersDtGr;
@Autowired
private FileStorage fileStorage;
@Subscribe
public void onInit(InitEvent event) {
Grid.Column<User> pictureColumn = usersDtGr.addComponentColumn(user -> { (1)
FileRef fileRef = user.getPicture();
if (fileRef != null) {
Image image = uiComponents.create(Image.class); (2)
image.setWidth("30px");
image.setHeight("30px");
image.setClassName("user-picture");
StreamResource streamResource = new StreamResource(
fileRef.getFileName(),
() -> fileStorage.openStream(fileRef));
image.setSrc(streamResource); (3)
return image; (4)
} else {
return new Span();
}
})
.setHeader("Picture")
.setAutoWidth(true)
.setFlexGrow(0);
usersDtGr.setColumnPosition(pictureColumn,0);
}
1 | 添加一列,显示 image 组件。 |
2 | Image 组件的实例使用 UiComponents 工厂创建。 |
3 | image 从给定的 StreamResource 获取内容,存储在 User 实体的 picture 属性中。 |
4 | addComponentColumn() 方法返回的可视化组件展示在列单元格中。 |
行内编辑
dataGrid
组件支持行内编辑器来编辑单元格数据。
带有 editable = true 属性的列展示实体属性编辑的组件。每个可编辑列的编辑组件是根据对应实体的属性自动选取的。
editorBuffered 属性定义行内编辑器是否启用缓存模式。缓存模式:修改后的数据需要显式提交。
-
如需将某些列设为可编辑,请设置 editable 属性为
true
。 -
然后,就可以通过编程的方式编辑某一行,参考 Vaadin 文档;或者定义 editorActionsColumn 元素,示例:
<dataGrid width="100%" dataContainer="usersDc" id="editableUsersTable"> <columns> <column property="username"/> <column property="firstName" editable="true"/> <column property="lastName" editable="true"/> <column property="active" editable="true"/> <column property="onboardingStatus"/> <editorActionsColumn width="8em" flexGrow="0"> <editButton text="Edit" icon="PENCIL"/> <closeButton text="Close" icon="CLOSE"/> </editorActionsColumn> </columns> </dataGrid>
editorActionsColumn
editorActionsColumn
元素用来创建自定义带编辑按钮的列。
<editorActionsColumn width="16em" flexGrow="0">
<editButton text="Edit" icon="PENCIL"/>
<saveButton icon="CHECK" themeNames="success"/>
<cancelButton icon="CLOSE" themeNames="error"/>
<closeButton text="Close" icon="CLOSE"/>
</editorActionsColumn>
编辑列中可以包含下列按钮:
-
editButton
- 开始编辑。适用于缓存或非缓存模式。 -
saveButton
- 保存编辑列中的改动。适用于缓存模式。 -
cancelButton
- 丢弃编辑列中的改动。适用于缓存模式。 -
closeButton
- 关闭编辑模式。仅适用于非缓存模式。
每个按钮仅支持标准按钮的有限几个属性:text、icon
、title、classNames、themeNames、iconAfterText
。
编辑列会相对其他列添加到表格中。如果是 includeAll="true"
,编辑列添加在最后。
DataGridEditor
io.jmix.flowui.component.grid.editor.DataGridEditor
接口提供了更多的编辑器功能:配置编辑器、打开编辑器、保存和取消行编辑以及定义列编辑组件的一些工具方法。
为了支持框架的底层机制,例如数据容器、源值等,列编辑组件必须通过 DataGridEditor 的方法(DataGridEditor#setColumnEditorComponent() )进行添加,不能直接使用列 API 的 Column#setEditorComponent() 方法。
|
示例:
@Autowired
private UiComponents uiComponents;
@ViewComponent
private DataGrid<User> editableUserTable;
@Subscribe
public void onInit(InitEvent event) {
DataGridEditor<User> editor = editableUserTable.getEditor(); (1)
editor.setColumnEditorComponent("timeZoneId", generationContext -> {
//noinspection unchecked
JmixComboBox<String> timeZoneField = uiComponents.create(JmixComboBox.class); (2)
timeZoneField.setItems(List.of(TimeZone.getAvailableIDs()));
timeZoneField.setValueSource(generationContext.getValueSourceProvider().getValueSource("timeZoneId"));
timeZoneField.setWidthFull();
timeZoneField.setClearButtonVisible(true);
timeZoneField.setRequired(true);
//noinspection unchecked,rawtypes
timeZoneField.setStatusChangeHandler(((Consumer) generationContext.getStatusHandler())); (3)
return timeZoneField; (4)
});
}
1 | 获取 DataGridEditor 实例。 |
2 | JmixComboBox 组件实例用 UiComponents 工厂创建。 |
3 | 设置 StatusChangeHandler. |
4 | setColumnEditorComponent() 方法返回的可视化组件将作为列编辑组件。 |
SupportsStatusChangeHandler
默认情况下,字段组件(例如,textField、comboBox)会在组件上方展示错误信息。但是在区域有限的单元格编辑器中,这种方式就不合适了。io.jmix.flowui.component.SupportsStatusChangeHandler
接口支持定义以不同的方式展示错误信息。实现了这个接口的组件支持错误信息代理。
行内编辑器默认使用 StatusChangeHandler
,会将错误信息作为组件的 title 展示。
双击编辑
有时候我们需要通过双击的方式打开行内编辑器。示例:
<dataGrid width="100%" dataContainer="usersDc" id="dblClickTable">
<columns>
<column property="username"/>
<column property="firstName" editable="true"/>
<column property="lastName" editable="true"/>
<column property="active" editable="true"/>
<column property="onboardingStatus"/>
</columns>
</dataGrid>
@ViewComponent
private DataGrid<User> dblClickTable;
@Subscribe
public void onInit(InitEvent event) {
DataGridEditor<User> tableEditor = dblClickTable.getEditor();
dblClickTable.addItemDoubleClickListener(e -> {
tableEditor.editItem(e.getItem());
Component editorComponent = e.getColumn().getEditorComponent();
if (editorComponent instanceof Focusable) {
((Focusable) editorComponent).focus();
}
});
}
XML 属性
id - allRowsVisible - classNames - colspan - columnReorderingAllowed - dataContainer - detailsVisibleOnClick - dropMode - editorBuffered - enabled - height - maxHeight - maxWidth - metaClass - minHeight - minWidth - nestedNullBehavior - pageSize - rowDraggable - selectionMode - tabIndex - themeNames - visible - width
allRowsVisible
如果 allRowsVisible
属性设置为 true
,数据网格的高度由数据行数决定。会从 DataProvider
中读取所有数据并展示,dataGrid
不带垂直滚动条。
allRowsVisible = true 会禁用数据网格的垂直滚动条,所有数据会一次性在 DOM 渲染。如果数据网格有大量数据,会有性能问题,不推荐使用该功能。
|
columnReorderingAllowed
dataGrid
提供拖放功能,支持用户调整数据网格中的列顺序。
列重排的功能默认是关闭的。需要设置 columnReorderingAllowed = true
开启。
列重排可以通过事件 ColumnReorderEvent 跟踪。
dropMode
设置拖放时的放置模式。当设置为非 null
时,dataGrid
会在数据放置到数据网格或某一行是发送事件。
支持四种不同的放置模式:BETWEEN
、ON_TOP
、ON_TOP_OR_BETWEEN
、ON_GRID
。
事件和处理器
AttachEvent - BlurEvent - CellFocusEvent - ColumnReorderEvent - ColumnResizeEvent - DetachEvent - FocusEvent - GridDragEndEvent - GridDragStartEvent - GridDropEvent - ItemClickEvent - ItemDoubleClickEvent - SortEvent - classNameGenerator - dataGenerator - dragFilter - dropFilter
在 Jmix Studio 生成处理器桩代码时,可以使用 Jmix UI 组件面板的 Handlers 标签页或者视图类顶部面板的 Generate Handler 添加,也可以通过 Code → Generate 菜单(Alt+Insert / Cmd+N)生成。 |
CellFocusEvent
当数据网格的某个单元格获得焦点时,发送 com.vaadin.flow.component.grid.CellFocusEvent
。对应 grid-cell-focus
DOM 事件。
ColumnReorderEvent
当数据网格的列重排时,发送 com.vaadin.flow.component.grid.ColumnReorderEvent
。对应 column-reorder-all-columns
DOM 事件。
ColumnResizeEvent
当用户改变数据网格列大小时,发送 com.vaadin.flow.component.grid.ColumnResizeEvent
。对应 column-drag-resize
DOM 事件。
GridDragEndEvent
当数据网格的行拖放结束时,发送 com.vaadin.flow.component.grid.dnd.GridDragEndEvent
。对应 grid-dragend
DOM 事件。
GridDragStartEvent
当数据网格的行拖放开始时,发送 com.vaadin.flow.component.grid.dnd.GridDragStartEvent
。对应 grid-dragstart
DOM 事件。
GridDropEvent
当拖放事件发生在数据网格或数据行时,发送 com.vaadin.flow.component.grid.dnd.GridDropEvent
。对应 grid-drop
DOM 事件。
ItemDoubleClickEvent
当双击数据网格时,发送 com.vaadin.flow.component.grid.ItemDoubleClickEvent
。对应 item-double-click
DOM 事件。
dragFilter
为拖放源设置拖动过滤器。
当 rowDraggable = true 时,默认所有可见行都可以拖动。
可以用拖动过滤器指定哪些行支持拖动。该方法接收某一行数据作为输入,如果该行支持拖动,则返回 true
。参考 com.vaadin.flow.component.grid.Grid
。