如何创建含跨列分区标题的JavaFX TableView?
实现带分区标题的JavaFX TableView
完全可以实现你要的效果,通过自定义TableRow并在数据源中插入分区标题行,就能让标题横跨整个表格宽度。以下是基于你现有代码的具体实现方案:
1. 扩展数据模型
创建抽象父类统一普通数据行和标题行的类型,避免类型转换问题:
public abstract class TableRowItem {}
修改你的FacilityRow继承该父类:
public class FacilityRow extends TableRowItem { private String number; private String type; private String heatingValue; private String measurementCenter; public FacilityRow() {} public FacilityRow(String number, String type, String heatingValue, String measurementCenter) { this.number = number; this.type = type; this.heatingValue = heatingValue; this.measurementCenter = measurementCenter; } // 原有getter和setter方法不变 public String getNumber() { return number; } public void setNumber(String number) { this.number = number; } public String getType() { return type; } public void setType(String type) { this.type = type; } public String getHeatingValue() { return heatingValue; } public void setHeatingValue(String heatingValue) { this.heatingValue = heatingValue; } public String getMeasurementCenter() { return measurementCenter; } public void setMeasurementCenter(String measurementCenter) { this.measurementCenter = measurementCenter; } }
新增分区标题类:
public class SectionTitle extends TableRowItem { private final String title; public SectionTitle(String title) { this.title = title; } public String getTitle() { return title; } }
2. 修改TableView配置
更新FXML中的TableView泛型,并调整列的cellValueFactory:
@FXML private TableView<TableRowItem> accommodationsOrBusinessesTableView; @FXML private TableColumn<TableRowItem, String> numberTableColumn; @FXML private TableColumn<TableRowItem, String> typeTableColumn; @FXML private TableColumn<TableRowItem, String> heatingValueTableColumn; @FXML private TableColumn<TableRowItem, String> measurementCenterTableColumn; @Override public void initialize(URL arg0, ResourceBundle arg1) { // 重新设置列的值工厂,适配新的泛型 numberTableColumn.setCellValueFactory(cellData -> { if (cellData.getValue() instanceof FacilityRow) { return new SimpleStringProperty(((FacilityRow) cellData.getValue()).getNumber()); } return null; }); typeTableColumn.setCellValueFactory(cellData -> { if (cellData.getValue() instanceof FacilityRow) { return new SimpleStringProperty(((FacilityRow) cellData.getValue()).getType()); } return null; }); heatingValueTableColumn.setCellValueFactory(cellData -> { if (cellData.getValue() instanceof FacilityRow) { return new SimpleStringProperty(((FacilityRow) cellData.getValue()).getHeatingValue()); } return null; }); measurementCenterTableColumn.setCellValueFactory(cellData -> { if (cellData.getValue() instanceof FacilityRow) { return new SimpleStringProperty(((FacilityRow) cellData.getValue()).getMeasurementCenter()); } return null; }); // 自定义行渲染逻辑,处理分区标题 accommodationsOrBusinessesTableView.setRowFactory(tv -> new TableRow<TableRowItem>() { @Override protected void updateItem(TableRowItem item, boolean empty) { super.updateItem(item, empty); if (empty || item == null) { setText(null); setGraphic(null); getStyleClass().remove("section-title-row"); return; } if (item instanceof SectionTitle) { // 创建标题标签并设置样式 Label titleLabel = new Label(((SectionTitle) item).getTitle()); titleLabel.getStyleClass().add("section-title"); // 使用HBox让标题居左并添加内边距 HBox titleContainer = new HBox(titleLabel); titleContainer.setAlignment(Pos.CENTER_LEFT); titleContainer.setPadding(new Insets(6, 0, 6, 12)); setGraphic(titleContainer); getStyleClass().add("section-title-row"); // 隐藏所有列,让标题看起来横跨整行 tv.getColumns().forEach(col -> col.setVisible(false)); } else { // 恢复列可见,显示普通数据行 tv.getColumns().forEach(col -> col.setVisible(true)); getStyleClass().remove("section-title-row"); setGraphic(null); } } }); // 构造带分区的数据 ObservableList<TableRowItem> tableData = FXCollections.observableArrayList(); // 添加Logements分区 tableData.add(new SectionTitle("Logements")); tableData.addAll(getLogementsFacilities()); // 替换为你的Logements数据列表 // 添加Commerces分区 tableData.add(new SectionTitle("Commerces")); tableData.addAll(getCommercesFacilities()); // 替换为你的Commerces数据列表 accommodationsOrBusinessesTableView.setItems(tableData); } // 示例数据获取方法,根据实际业务替换 private List<FacilityRow> getLogementsFacilities() { return List.of( new FacilityRow("L001", "Appartement", "120 kWh", "Centre A"), new FacilityRow("L002", "Maison", "250 kWh", "Centre B") ); } private List<FacilityRow> getCommercesFacilities() { return List.of( new FacilityRow("C001", "Boutique", "300 kWh", "Centre A"), new FacilityRow("C002", "Bureau", "180 kWh", "Centre C") ); }
3. 添加CSS样式美化
在FXML对应的CSS文件中添加以下样式,让分区标题更醒目:
.section-title-row { -fx-background-color: #f0f0f0; -fx-border-color: #cccccc; -fx-border-width: 1px 0; } .section-title { -fx-font-size: 14px; -fx-font-weight: bold; -fx-text-fill: #2c3e50; }
关键说明
- 通过自定义
TableRow,可以区分普通数据行和标题行,动态控制列的显示/隐藏,实现标题横跨整行的效果 - 使用抽象父类统一类型,避免渲染时出现类型转换异常
- CSS样式可根据需求自由调整,比如背景色、字体大小等
内容的提问来源于stack exchange,提问作者Anon
相关产品推荐
相关产品推荐

