You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何创建含跨列分区标题的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 10:52:33