如何在JavaFX的TableView中创建带前置省略号的列?
实现JavaFX TableView路径列的前置省略号显示
需求:TableView中存储路径的列,所有路径属于同一根目录,当路径长度超出列宽时,仅显示路径末尾并添加前置省略号,示例:
..someverylongdirectoryname/file.txt ..omeverylongdirectoryname/file2.txt
尝试的代码未能实现预期效果:
public class JavaFxTest extends Application { public static class FilePath { private final String path; public FilePath(String path) { this.path = path; } public String getPath() { return path; } } @Override public void start(Stage primaryStage) { TableView<FilePath> tableView = new TableView<>(); TableColumn<FilePath, String> pathColumn = new TableColumn<>("Path"); pathColumn.setCellValueFactory(new PropertyValueFactory<>("path")); pathColumn.setPrefWidth(200); pathColumn.setCellFactory(column -> new javafx.scene.control.TableCell<>() { private final Text text = new Text(); @Override protected void updateItem(String item, boolean empty) { super.updateItem(item, empty); if (empty || item == null) { setGraphic(null); } else { text.setText(item); text.setStyle("-fx-text-alignment: right;"); setGraphic(text); } } }); tableView.getColumns().add(pathColumn); tableView.getItems().addAll( new FilePath("/usr/local/bin/someverylongdirectoryname/file.txt"), new FilePath("/usr/local/bin/someverylongdirectoryname/file2.txt") ); primaryStage.setScene(new Scene(tableView, 300, 200)); primaryStage.show(); } public static void main(String[] args) { launch(args); } }
解决方案
要实现前置省略号的效果,需要手动计算文本宽度并截断前缀,同时监听列宽变化以动态更新显示内容。修改后的代码如下:
public class JavaFxTest extends Application { public static class FilePath { private final String path; public FilePath(String path) { this.path = path; } public String getPath() { return path; } } @Override public void start(Stage primaryStage) { TableView<FilePath> tableView = new TableView<>(); TableColumn<FilePath, String> pathColumn = new TableColumn<>("Path"); pathColumn.setCellValueFactory(new PropertyValueFactory<>("path")); pathColumn.setPrefWidth(200); pathColumn.setCellFactory(column -> new TableCell<>() { private final Text text = new Text(); // 保存原始路径,方便列宽变化时重新计算 private String originalPath; { // 监听列宽度变化,重新更新显示内容 column.widthProperty().addListener((obs, oldWidth, newWidth) -> { if (originalPath != null && !isEmpty()) { updateDisplayText(originalPath, newWidth.doubleValue()); } }); // 设置文本对齐为右对齐,让末尾内容对齐 text.setStyle("-fx-text-alignment: right;"); } @Override protected void updateItem(String item, boolean empty) { super.updateItem(item, empty); if (empty || item == null) { setGraphic(null); originalPath = null; } else { originalPath = item; updateDisplayText(item, column.getWidth()); setGraphic(text); } } private void updateDisplayText(String path, double columnWidth) { // 减去TableCell的默认内边距,避免计算误差 double availableWidth = columnWidth - 10; text.setText(path); // 如果文本宽度小于等于可用宽度,直接显示 if (text.getLayoutBounds().getWidth() <= availableWidth) { return; } // 逐步截断前缀,直到文本宽度符合要求 String truncatedPath = path; // 最小保留长度,避免过度截断 final int minLength = 10; while (text.getLayoutBounds().getWidth() > availableWidth && truncatedPath.length() > minLength) { // 从第一个斜杠后截断,保留末尾并添加前置省略号 int firstSlashIndex = truncatedPath.indexOf('/'); if (firstSlashIndex == -1) { // 无斜杠时直接从开头截断 truncatedPath = ".." + truncatedPath.substring(2); } else { truncatedPath = ".." + truncatedPath.substring(firstSlashIndex + 1); } text.setText(truncatedPath); } } }); tableView.getColumns().add(pathColumn); tableView.getItems().addAll( new FilePath("/usr/local/bin/someverylongdirectoryname/file.txt"), new FilePath("/usr/local/bin/someverylongdirectoryname/file2.txt") ); primaryStage.setScene(new Scene(tableView, 300, 200)); primaryStage.show(); } public static void main(String[] args) { launch(args); } }
关键说明
- 保存原始路径:在TableCell中存储原始路径,避免列宽变化时丢失完整数据。
- 监听列宽变化:当列宽度调整时,自动重新计算并更新显示文本,保证自适应宽度变化。
- 动态截断前缀:通过循环逐步截断路径的前缀部分,同时添加
..,直到文本宽度符合列宽限制,确保始终显示路径的末尾核心部分。 - 内边距调整:计算可用宽度时减去TableCell的默认内边距,避免因内边距导致的显示误差。
内容的提问来源于stack exchange,提问作者SilverCube
相关产品推荐
相关产品推荐

