0%

JavaFX渲染子表格

之前有讲过,最近在开发一个以 JavaFX 为技术栈的桌面端项目。之前解决了表格数据刷新的问题:JavaFX使用MapValueFactory渲染表格数据时的数据刷新问题。最近又碰到一个问题:需要为指定的行加载子表格。

StackOverFlow 上找到了一个 DemoJavaFX SubTable Demo。渲染效果如下:

直接将代码拷贝到现有项目中,关键代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// 点击父表格某一行,展开子表格
tableView.setRowFactory(tv -> new TableRow<Map<String, Object>>() {
Node detailsPane;
{
this.selectedProperty().addListener((obs, wasSelected, isNowSelected) -> {
// 由于当前页面存在轮询任务,因此这里需要筛选一下,只处理主线程
if ("JavaFX Application Thread".equals(Thread.currentThread().getName())) {
if (isNowSelected) {
Map<String, Object> selectedItem = tv.getSelectionModel().getSelectedItem();
List<Map<String, Object>> subTableItems = childSensorMap.get(selectedItem.get("sensor_code").toString());
if (CollectionUtils.isNotEmpty(subTableItems)) {
detailsPane = constructSubTable(FXCollections.observableArrayList(subTableItems));
this.getChildren().add(detailsPane);
}
} else {
if (detailsPane != null) {
this.getChildren().remove(detailsPane);
detailsPane = null;
}
}
}
// this.requestLayout();
});
}
@Override
protected double computePrefHeight(double width) {
if (isSelected() && detailsPane != null) {
return super.computePrefHeight(width) + detailsPane.prefHeight(60);
} else {
return super.computePrefHeight(width);
}
}

@Override
protected void layoutChildren() {
super.layoutChildren();
if (isSelected() && detailsPane != null) {
double width = getWidth();
double paneHeight = detailsPane.prefHeight(width);
detailsPane.resizeRelocate(0, getHeight() - paneHeight, width, paneHeight);
}
}
});

Web 端实现的子表格是有首行缩进效果,这里也遵循原样式,子表格的样式代码如下:

1
2
3
4
5
6
7
subTable.getColumns().addAll(list);
subTable.setItems(items);
// 设置子表格高度
subTable.setPrefHeight(60 + (items.size() * 47));
// 设置左侧缩进
subTable.setPadding(new Insets(0, 0, 0, 50));
subTable.setStyle("-fx-border-color: #42bff4;");

最终实现效果如下:

参考文档

Javafx Tables inside row table

JavaFX SubTable Demo