如何通过代码(非FXML)实现JavaFX TableColumn表头左对齐?
JavaFX 17 实现单个TableColumn表头对齐(程序化方式)
问题描述
我在JavaFX 17中尝试将TableColumn表头设置为左对齐,希望通过Java代码(程序化方式)实现,不使用FXML。我可以通过为场景添加Base64编码的样式表URL全局设置对齐,但不知道如何仅修改单个TableColumn表头的对齐方式。尝试通过setStyle(...)设置各类CSS均无效。
解决方案
感谢@DavidWeber的帮助,我采纳了他的建议(并使用了JDK switch/null预览特性)。以下是最终实现代码:
package com.stackoverflow.question; import java.util.function.Function; import javafx.application.Application; import javafx.application.Platform; import javafx.beans.property.ReadOnlyObjectWrapper; import javafx.collections.FXCollections; import javafx.collections.transformation.SortedList; import javafx.geometry.Pos; import javafx.scene.Scene; import javafx.scene.control.Label; import javafx.scene.control.TableColumn; import javafx.scene.control.TableView; import javafx.scene.control.skin.TableColumnHeader; import javafx.stage.Stage; public final class TableColumnAlignment extends Application { private record RowData(String left, Integer right) {} private static final String TITLE_LEFT = "Left"; private static final String TITLE_RIGHT = "Right"; @Override public void start(final Stage stage) throws Exception { final var colLeft = buildColumn("colLeft", TITLE_LEFT, RowData :: left); final var colRight = buildColumn("colRight", TITLE_RIGHT, RowData :: right); ; colRight.setStyle("-fx-alignment: center-right"); final var sortedList = new SortedList<RowData>(FXCollections.observableArrayList(FXCollections.observableArrayList( new RowData("Left Column Header should be Left-Justified!", 123456789), new RowData("This Cell is left justified ok", 789), new RowData("Right Column Header should be Right-Justified!", 456789) ))); final var table = new TableView<RowData>(); ; table.getColumns().add(colLeft); ; table.getColumns().add(colRight); ; table.setItems(sortedList); sortedList.comparatorProperty().bind(table.comparatorProperty()); Platform.runLater(() -> { table.lookupAll(".column-header > .label").forEach(node -> { if (node.getParent() instanceof TableColumnHeader && node instanceof Label nodeLabel) { switch(nodeLabel.getText()) { case TITLE_LEFT -> nodeLabel.setAlignment(Pos.CENTER_LEFT); case TITLE_RIGHT -> nodeLabel.setAlignment(Pos.CENTER_RIGHT); } System.out.println(nodeLabel + "\t" + nodeLabel.getText()); } }); }); stage.setTitle("Table Column Alignment"); stage.setScene(new Scene(table, 500, 200)); stage.show(); } private <T, V> TableColumn<T, V> buildColumn(final String id, final String title, final Function<T, V> getter) { final var tableColumn = new TableColumn<T, V>(title); ; tableColumn.setId(id); ; tableColumn.setCellValueFactory((cellDataFeatures) -> { final T bean = cellDataFeatures.getValue(); final V beanPropertyValue = getter.apply(bean); return new ReadOnlyObjectWrapper<V>(beanPropertyValue); }); return tableColumn; } public static void main(final String[] args) { launch(args); } }
核心思路
- 使用
Platform.runLater()确保UI组件渲染完成后再操作表头元素,避免出现查找不到节点的情况 - 通过
lookupAll(".column-header > .label")定位所有表头的Label组件 - 根据表头文本匹配目标列,调用
Label.setAlignment()单独设置对应表头的对齐方式
原始问题代码
package com.stackoverflow.question; import java.nio.charset.StandardCharsets; import java.util.Base64; import java.util.function.Function; import javafx.application.Application; import javafx.beans.property.ReadOnlyObjectWrapper; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.scene.Scene; import javafx.scene.control.TableColumn; import javafx.scene.control.TableView; import javafx.stage.Stage; public final class TableColumnAlignment extends Application { private record RowData(String left, Integer right) {} @Override public void start(final Stage stage) throws Exception { final var colLeft = buildTableColumn("Left", RowData :: left); final var colRight = buildTableColumn("Right", RowData :: right); colLeft .setId("colLeft"); colRight.setId("colRight"); colLeft.setStyle("-fx-alignment: center-left; -fx-background-color: yellow"); final var table = new TableView<RowData>(); addColumns(table.getColumns(), colLeft, colRight); ; table.setItems(FXCollections.observableArrayList( new RowData("Left Column Header should be Left-Justified!", 123456789), new RowData("This Cell is left justified ok", 789), new RowData("Right Column Header should be Right-Justified!", 456789) )); final var scene = new Scene(table, 500, 200); // ; scene.getStylesheets().add(encodeStyleAsURL(".column-header .label {-fx-alignment: center-left}")); stage.setTitle("Table Column Alignment"); stage.setScene(scene); stage.show(); } public static String encodeStyleAsURL(final String cssStyle) { final var cssBytes = cssStyle.getBytes(StandardCharsets.UTF_8); final var cssBytesBase64 = Base64.getEncoder().encodeToString(cssBytes); return "data:text/css;base64," + cssBytesBase64; } private <T, V> TableColumn<T, V> buildTableColumn(final String title, final Function<T, V> beanPropertyGetter) { final var tableColumn = new TableColumn<T, V>(title); ; tableColumn.setCellValueFactory((cellDataFeatures) -> { final T bean = cellDataFeatures.getValue(); final V beanPropertyValue = beanPropertyGetter.apply(bean); return new ReadOnlyObjectWrapper<V>(beanPropertyValue); }); return tableColumn; } @SafeVarargs private final <T> void addColumns(final ObservableList<TableColumn<T, ?>> columnList, final TableColumn<T, ?>... columns) { columnList.addAll(columns); } public static void main(final String[] args) { launch(args); } }
内容的提问来源于stack exchange,提问作者Dave The Dane
相关产品推荐
相关产品推荐

