【问题标题】:JavaFx Text wrap in TableCellTableCell 中的 JavaFx 文本换行
【发布时间】:2020-09-01 00:38:03
【问题描述】:

我在 TableCells 中的文本换行有问题,如果我更改单元格的数据,其中之一是文本换行不能自动工作,就像我做一些 hack 一样。我很好奇是否有人遇到了与我相同的问题,并且可能找到了更好的解决方案。

这是一个您可以验证的简单示例:

public class Controller implements Initializable {

    @FXML
    private TableView<Model> table;
    @FXML
    private TableColumn<Model, String> colA;
    @FXML
    private TableColumn<Model, String> colB;
    @FXML
    private Button changeString;

    @Override
    public void initialize(URL location, ResourceBundle resources) {

        colA.setCellValueFactory(data -> data.getValue().stringA);
        colB.setCellValueFactory(data -> data.getValue().stringB);

        setCellFactory();

        ObservableList<Model> items = FXCollections.observableArrayList();

        items.add(new Model("This is a long string that needs to be wrapped", "Short"));
        items.add(new Model("This is a long string that needs to be wrapped", "Short"));

        changeString.setOnAction(event -> {
            table.getItems().get(0).getStringA().setValue("Short");
            table.getColumns().get(0).setVisible(false);
            table.getColumns().get(0).setVisible(true);
        });

        table.setItems(items);
    }

    private void setCellFactory() {
        colA.setCellFactory(f -> {
            TableCell<Model, String> cell = new TableCell<Model, String>() {
                Text text = new Text();

                @Override
                protected void updateItem(String item, boolean empty) {
                    super.updateItem(item, empty);
                    if (empty) {
                        setGraphic(null);
                        return;
                    }
                    text.setWrappingWidth(getTableColumn().getWidth() - 10);
                    text.setText(item);
                    setGraphic(text);
                }
            };
            return cell;
        });
    }

    @Getter
    private static class Model {

        private final StringProperty stringA;
        private final StringProperty stringB;

        private Model(String stringA, String stringB) {
            this.stringA = new SimpleStringProperty(stringA);
            this.stringB = new SimpleStringProperty(stringB);
        }
    }
}

(这只是相关部分,如果需要,我将包括Mainfxml

如您所见,我必须在模型中设置一个值,该值显示在表格单元格中,但设置后单元格的高度不会更新。我为了更新它,我必须包含该列隐藏/显示黑客以刷新高度。

您对这个问题有更好的建议/解决方案吗?

【问题讨论】:

  • 参见stackoverflow.com/a/44128787/3625077,将 wrappingWidthProperty 与列 widthProperty 绑定
  • 这没有帮助...我每次在文本设置为图形之前设置 wrappingWidth。
  • 您需要Text 吗?默认情况下不管理形状,因此单元格高度不会自动更改我并不感到惊讶。单元格高度通常是有问题的,但如果您直接在单元格上调用方法(setWrapText(...)setText(...) 等),它是否有效。或者,在最坏的情况下,为图形使用Label
  • @James_D 我都试过了。 setWrapText 什么都不做,它会在文本末尾剪切 ... 但它不会显示整个文本,因此它根本不会更新单元格的高度。使用标签是一样的,它没有wrappingWIdth 属性来绑定它。在每个与 wraptext 相关的问题中,我只发现这个基于 Text 的问题。这在某种程度上可行,但刷新部分不是很好。
  • hmm ... 看起来行中 prefHeight 的计算发生在 单元格内容更新之前。试图以某种方式强迫之后,没有成功,sry。顺便说一句(无助于解决您的问题,只是为了代码健全:) - 由于 wrappingWidth 与单元格内容无关,但与列宽无关,它应该绑定到该属性(防止无列,当然)在 updateItem 之外。

标签: javafx javafx-8 word-wrap


【解决方案1】:

这与您的 setCellFactory 中的 updateItem 在主线程中有关。像这样更改您的单元工厂以在 FX 线程中运行

                @Override
                protected void updateItem(String item, boolean empty) {
                    super.updateItem(item, empty);
                    Platform.runLater(() -> {
                        if (empty) {
                            setGraphic(null);
                        } else {
                            text.wrappingWidthProperty().bind(getTableColumn().widthProperty().subtract(10));
                            text.setText(item);
                            setGraphic(text);
                        }
                    });

                }
            };
        });
    }

您可以在 changeString.setOnAction 事件中移除可见的 hack 列

或者,由于认为runLater 是一个黑客,因此使用 tableview 刷新...仅使用您的原始代码 sn-p,而不是

       changeString.setOnAction(event -> {
            table.getItems().get(0).getStringA().setValue("Short");
            table.getColumns().get(0).setVisible(false);
            table.getColumns().get(0).setVisible(true);
        });

用这个替换

       changeString.setOnAction(event -> {
            table.getItems().get(0).getStringA().setValue("Short");
            table.refresh();
        });

【讨论】:

  • .. 看起来它可能有效(我假设您已经测试过?),如果是这样,您应该在 updateItem 之外进行绑定(请阅读我对问题的评论:)至于 hack 级别:使用runlater 与 hide/show 处于同一级别 .. 但是当涉及到边界错误时,任何事情都可以:)
  • 我测试过,fx 线程中的绑定是有效的,但我同意宽度绑定应该在初始化方法中。在没有看到 OP 的完整代码的情况下,这在很大程度上取决于他如何设置表格列的(pref)宽度。
  • 好奇:为什么它会依赖于 pref 设置?列是否可以调整大小,绑定到宽度将在前者而不是在后一种情况下工作。重复:wrappingWidth依赖于内容,而是依赖于列宽,所以它不属于updateItem。
  • 测试时,我在 fxml 或控制器中没有列宽的代码,并且列将以 1 个字符宽度绘制。如果我设置一个首选项宽度,比如 40,列将在 40 处换行,并且当按下按钮事件被触发时,会根据 OP 的需要自动调整 hright 的大小
  • 这是不寻常的行为(没有任何明确设置列的皮肤大小默认为 80).. 但感谢您提供信息 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-18
  • 2014-05-09
  • 1970-01-01
  • 2015-07-22
  • 2020-01-21
相关资源
最近更新 更多