1

I try to align the vertical scroll position of two javafx.scene.control.ScrollPanes via

sp1.vvalueProperty().bindBidirectional(sp2.vvalueProperty());

The problem is that one of these ScrollPanes may have a horizontal scroll bar. So the more I scroll down the ScrollPanes, the more they get misaligned (see screenshot). How can I handle this?

javafx scollpane misaligned

Sebastian
  • 5,721
  • 3
  • 43
  • 69
  • 1
    You could make both/all `ScrollPane`s always have a horizontal scroll bar or never have a horizontal scroll bar. See [`ScrollPane.hbarPolicy`](https://docs.oracle.com/javase/10/docs/api/javafx/scene/control/ScrollPane.html#hbarPolicyProperty). – Slaw Sep 02 '18 at 18:35

1 Answers1

2

It's impossible to do this with 2 ScrollPanes and contents of equal height unless you display the scrollbar in both ScrollPanes:

Consider the case where the content fits the viewport of the left ScrollPane exactly. The viewPort of the right ScrollPane can be scrolled by the ScrollBar height. Modifying the left ScrollPane is not possible.

Since the expected result seems to be some kind of scale, you could simply use a Pane with a child you apply transformY to and a clip. The formula to calculate the pixel to be placed at the top, use

top = vvalue * (contentHeight - viewportHeight)

Example

private static Label createLabel(int num, boolean mark) {
    Label label = new Label(Integer.toString(num));
    label.setPrefSize(50, 50);
    label.setMaxSize(Double.MAX_VALUE, Region.USE_PREF_SIZE);
    label.setStyle(mark ? "-fx-background-color: #FFFFFF" : "-fx-background-color: #BBBBBB;");
    return label;
}

@Override
public void start(Stage primaryStage) throws Exception {
    VBox scale = new VBox();
    scale.setMinHeight(Region.USE_PREF_SIZE);
    GridPane content = new GridPane();

    for (int i = 0; i < 40; i++) {
        boolean b = ((i % 2) == 0);
        scale.getChildren().add(createLabel(i, !b));

        for (int j = 0; j < 10; j++) {
            content.add(createLabel(i * 10 + j, b), j, i);
        }
    }

    AnchorPane scaleContainer = new AnchorPane(scale);
    scaleContainer.setMinWidth(30);
    scaleContainer.setMinHeight(0);
    AnchorPane.setLeftAnchor(scale, 0d);
    AnchorPane.setRightAnchor(scale, 0d);

    Rectangle clip = new Rectangle();
    scaleContainer.setClip(clip);
    clip.widthProperty().bind(scaleContainer.widthProperty());
    clip.heightProperty().bind(scaleContainer.heightProperty());

    ScrollPane scroll = new ScrollPane(content);

    scale.translateYProperty().bind(Bindings.createDoubleBinding(() -> {
        double contentHeight = content.getHeight();
        double viewportHeight = scroll.getViewportBounds().getHeight();
        if (contentHeight <= viewportHeight) {
            return 0d;
        } else {
            return -scroll.getVvalue() * (contentHeight - viewportHeight);
        }
    }, scroll.viewportBoundsProperty(), scroll.vvalueProperty(), content.heightProperty()));

    HBox root = new HBox(scaleContainer, scroll);
    root.setPadding(new Insets(10));

    Scene scene = new Scene(root, 400, 400);

    primaryStage.setScene(scene);
    primaryStage.show();
}
fabian
  • 80,457
  • 12
  • 86
  • 114