Harkan
Harkan

Reputation: 192

JavaFX : Keep line bound to the center of two panes

I'm new to JavaFX and I have troubles with bindings. I'm coding a game in which I draw lines between panes contains in the cells of a GridPane. I can draw lines with the code below, but I'd like to have the line coordinates to scale as the pane gets bigger when I resize the window.

The Panes and the GridPane already resize as wanted, and I've managed to bind the line's width to the size of the scene (cellSize is a binding on the scene width/height).

Pane lastPane = panes[lastC][lastR];
Pane curPane = panes[c][r];

Bounds boundsInSceneLast = lastPane.localToScene(lastPane.getBoundsInLocal());
Bounds boundsInSceneCur = curPane.localToScene(curPane.getBoundsInLocal());
double lastX = (boundsInSceneLast.getMinX() + boundsInSceneLast.getMaxX())/2;
double lastY = (boundsInSceneLast.getMinY() + boundsInSceneLast.getMaxY())/2;
double x = (boundsInSceneCur.getMinX() + boundsInSceneCur.getMaxX())/2;
double y= (boundsInSceneCur.getMinY() + boundsInSceneCur.getMaxY())/2;

Line line = new Line(lastX, lastY, x, y);

line.setStroke(Color.web(couleurs.get(symbole)));
line.strokeWidthProperty().bind(cellSize.divide(10));
line.setStrokeLineCap(StrokeLineCap.BUTT);

anchor.getChildren().add(line);
lines.get(symbole).add(line);

anchor is an AnchorPane which is the root of my Scene and lines is a HashMap which keeps track of the lines, but those shouldn't be relevant to my problem.

I'm sure it can be done pretty simply but I've searched the web pretty deeply and all I could understand and try wasn't getting the job done so I'm asking for your help.

Thanks in advance !! :)

Upvotes: 0

Views: 418

Answers (1)

fabian
fabian

Reputation: 82461

It's problematic to listen to the bounds of a Node in the scene since there is no property for the scene bounds and every Parent on the path to the root node of the scene could apply a transform that require you to adjust the position of the line ends. This would require you to add a listener to descendant of the Panes.

It would be simpler to make the lines a part of the GridPane itself as unmanaged nodes. This allows you to work with the bounds of the nodes in the GridPane:

final Pane lastPane = panes[lastC][lastR];
final Pane curPane = panes[c][r];

final Line line = new Line();

line.setStroke(Color.web(couleurs.get(symbole)));
line.strokeWidthProperty().bind(cellSize.divide(10));
line.setStrokeLineCap(StrokeLineCap.BUTT);

InvalidationListener listener = o -> {
    Bounds boundsInSceneLast = lastPane.getBoundsInParent();
    Bounds boundsInSceneCur = curPane.getBoundsInParent();
    double lastX = (boundsInSceneLast.getMinX() + boundsInSceneLast.getMaxX())/2;
    double lastY = (boundsInSceneLast.getMinY() + boundsInSceneLast.getMaxY())/2;
    double x = (boundsInSceneCur.getMinX() + boundsInSceneCur.getMaxX())/2;
    double y = (boundsInSceneCur.getMinY() + boundsInSceneCur.getMaxY())/2;

    line.setStartX(lastX);
    line.setStartY(lastY);
    line.setEndX(x);
    line.setEndY(y);
};

// listen to location & size changes of panes in the GridPane
lastPane.boundsInParentProperty().addListener(listener);
curPane.boundsInParentProperty().addListener(listener);

// initial refresh
listener.invalidated(null);

// add line to GridPane without considering it for layout
line.setManaged(false);
gridPane.getChildren().add(line);

lines.get(symbole).add(line);

Upvotes: 1

Related Questions