Javafx,逐行滚动而不是逐页滚动的滚动 Pane

标签 java javafx scrollpane vbox

我有一个可滚动垂直框,里面有很多文本字段。我可以通过 TAB 键从一个文本字段浏览到下一个文本字段。当我到达当前可见的最后一个文本字段并再次按 TAB 时,滚动 Pane 会切换到下一个“页面”,并且光标位于新的最上面的文本字段中。

但是当我从文本字段跳转到可见区域底部的下一个文本字段时,我需要逐行滚动行为。

任何有想法的人。

  package test;

  import javafx.application.Application;
  import javafx.scene.Scene;
  import javafx.scene.control.ScrollPane;
  import javafx.scene.control.TextField;
  import javafx.scene.layout.HBox;
  import javafx.scene.layout.VBox;
  import javafx.stage.Stage;

  public class Scroller extends Application {

  @Override
  public void start(Stage primaryStage) {

    VBox vb = new VBox();
    for (int i = 0; i < 360; i++) {
        TextField x = new TextField(String.valueOf(i));
        vb.getChildren().add(x);
    }
    ScrollPane sp = new ScrollPane(vb);
    sp.setVbarPolicy(ScrollPane.ScrollBarPolicy.AS_NEEDED);
    sp.setFitToWidth(true);

    TextField tf = new TextField();
    HBox root = new HBox();
    root.getChildren().addAll(sp, tf);

    Scene scene = new Scene(root, 300, 250);

    primaryStage.setTitle("Hello World!");
    primaryStage.setScene(scene);
    primaryStage.show();
  }

  public static void main(String[] args) {
    launch(args);
}
}

最佳答案

内容坐标中顶部的坐标可以确定为

topY = (contentHeight - viewportHeight) * vValue

您可以使用此公式和场景的 focusedNode 属性的监听器将聚焦节点的底部滚动到视口(viewport)的底部:

public static boolean isChild(Parent parent, Node node) {
    while (node != null && node != parent) {
        node = node.getParent();
    }
    return parent == node;
}

@Override
public void start(Stage primaryStage) {
    VBox vb = new VBox();
    for (int i = 0; i < 360; i++) {
        TextField x = new TextField(String.valueOf(i));
        vb.getChildren().add(x);
    }
    ScrollPane sp = new ScrollPane(vb);
    sp.setVbarPolicy(ScrollPane.ScrollBarPolicy.AS_NEEDED);
    sp.setFitToWidth(true);

    TextField tf = new TextField();
    HBox root = new HBox();
    root.getChildren().addAll(sp, tf);

    Scene scene = new Scene(root, 300, 250);
    scene.focusOwnerProperty().addListener((o, oldVal, newVal) -> {
        if (isChild(vb, newVal)) {
            // get bounds of focused node in ScrollPane content
            Bounds bounds = newVal.getLayoutBounds();
            while (newVal != vb) {
                bounds = newVal.localToParent(bounds);
                newVal = newVal.getParent();
            }
            double h = vb.getHeight();
            double vH = sp.getViewportBounds().getHeight();

            // scroll node to bottom of the viewport if bottom is not in view
            if (bounds.getMaxY() > sp.getVvalue() * (h - vH) + vH) {
                sp.setVvalue((bounds.getMaxY() - vH) / (h - vH));
            }
        }
    });

    primaryStage.setTitle("Hello World!");
    primaryStage.setScene(scene);
    primaryStage.show();
}

关于Javafx,逐行滚动而不是逐页滚动的滚动 Pane ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48966258/

相关文章:

java - 如何国际化 jfreechart 中的日期值?

JavaFX - 仅显示一个标签

java - 如何在 Stage.show() 之后运行函数?

java - GridBagLayout 中的 JPanel 位置不正确

java - 正确答案进度条

java - 排除maven中的嵌套传递依赖

java - 如何将变量的全部内容发送/导出到文本文件/xml 文件/剪贴板?

java - 为什么有些节点有 x 和 y 位置而其他节点没有

java - 使用 JavaFX 将 ScrollPane 的内容居中并设置 fitToWidth=false

JavaFX 如何滚动 ScrollPane 以使节点位于视口(viewport)中间?