ScrollPane javafx自动滚动(设置vvalue为1.0)只滚动到最后一项之前

ScrollPane javafx auto scrolling (setting vvalue to 1.0) only scrolls to the item before the last

所以,情况是...我在滚动窗格中有一个 vbox。我将 hbox 添加到 vbox 中,然后在每次插入后调用 vbox.setVvalue(1.0)

然而,有 5 个水平框,滚动器只会使最后一个可见项目成为第 4 个水平框 - 在当前看到的下方有一个水平框(需要向下滚动才能看到)。

我找到了一个解决方案,它将滚动窗格的 vvalue 属性 绑定到 vbox 的高度 属性,如下所示:scrollPane.vvalueProperty().bind(vbox.heightProperty()) 我假设每次都会将 vvalue 更改为最大值vbox 高度更改的时间(即添加新的 hbox 时)。

但是,我仍然想提高我的知识,以及为什么第一个(在每次插入后设置滚动窗格的 vvalue)与绑定属性不同。谢谢!

设置新的 vvalue 发生在由修改 VBox 引起的布局传递之前,但结果在布局传递之前应用。由于视口中显示的顶部 y 坐标的公式为

top = max(0, vvalue * (contentHeight - viewportHeight))

并且在布局过程中,内容的左上角保持在原位,您会在视口底部看到旧内容的底部。

要解决此问题,您可以使用

ScrollPane 上手动触发布局传递
scrollPane.applyCss();
scrollPane.layout();

例子

@Override
public void start(Stage primaryStage) {
    VBox content = new VBox();
    ScrollPane scrollPane = new ScrollPane(content);
    VBox.setVgrow(scrollPane, Priority.ALWAYS);
    Button button = new Button("fill");
    button.setOnAction(evt -> {
        for (int i = 0; i < 20; i++) {
            content.getChildren().add(new Text(Integer.toString(i)));
        }
        System.out.println("content size before layout: " + content.getHeight());

        // manually layout scrollPane
        scrollPane.applyCss();
        scrollPane.layout();

        System.out.println("content size after layout: " + content.getHeight());
        scrollPane.setVvalue(1d);
    });

    Scene scene = new Scene(new VBox(button, scrollPane), 200, 200);
    primaryStage.setScene(scene);
    primaryStage.show();
}