Javafx,逐行滚动而不是逐页滚动的滚动窗格
Javafx, scrollpane with line-by-line scrolling not page-wise
我有一个 Scrollable-VBox,里面有很多 TextField。我可以通过 TAB 键从一个文本字段浏览到下一个文本字段。当我到达当前可见的最后一个并再次按 TAB 时,滚动窗格切换到下一个 "page" 并且光标位于新的最上面的文本字段中。
但是我需要逐行滚动行为,同时从文本字段跳到可见区域底部的下一个。
有想法的人。
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);
}
}
内容坐标中top的坐标可以确定为
topY = (contentHeight - viewportHeight) * vValue
您可以使用此公式和场景 focusedNode
属性 的侦听器将聚焦节点的底部滚动到视口底部:
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();
}
我有一个 Scrollable-VBox,里面有很多 TextField。我可以通过 TAB 键从一个文本字段浏览到下一个文本字段。当我到达当前可见的最后一个并再次按 TAB 时,滚动窗格切换到下一个 "page" 并且光标位于新的最上面的文本字段中。
但是我需要逐行滚动行为,同时从文本字段跳到可见区域底部的下一个。
有想法的人。
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);
}
}
内容坐标中top的坐标可以确定为
topY = (contentHeight - viewportHeight) * vValue
您可以使用此公式和场景 focusedNode
属性 的侦听器将聚焦节点的底部滚动到视口底部:
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();
}