GuroItuyoshi
GuroItuyoshi

Reputation: 63

Bind two Circle with a Path in JavaFX

I would like to bind two circles with a free form line using Path (by adding severals LineTo objects in the elements).

I don't know how to use bind on properties in the case of Path. Moreover I would like to change its color by clicking on it.

Here's an example of how it should looks.

Example of what I need

Example of what I need

Edit :

Each vertex can move with a setOnMouseDragged, So I need to keep each free form of line connected to the vertex.

Upvotes: 1

Views: 399

Answers (1)

fabian
fabian

Reputation: 82461

Just bind the x and y properties of the first MoveTo and the last LineTo to the centerX and centerY coordinates where the path starts/ends.

private Path constructionPath = null;
private final Map<Color, Color> nextColor;

{
    // create map for modifying color
    nextColor = new HashMap<>();
    Color[] colors = new Color[] { Color.BLACK, Color.RED, Color.GREEN, Color.BLUE };
    for (int i = 0; i < colors.length - 1; i++) {
        nextColor.put(colors[i], colors[i+1]);
    }
    nextColor.put(colors[colors.length-1], colors[0]);
}

private void createCircle(MouseEvent evt, Pane canvas) {
    Circle circle = new Circle(evt.getX(), evt.getY(), 5, Color.WHITE);
    circle.setStroke(Color.BLACK);
    circle.setStrokeWidth(2.5);

    // circle dragging events
    class DragListener implements EventHandler<MouseEvent> {

        boolean dragging;
        double startX;
        double startY;

        @Override
        public void handle(MouseEvent event) {
            Point2D pt = circle.localToParent(event.getX(), event.getY());
            circle.setCenterX(pt.getX() + startX);
            circle.setCenterY(pt.getY() + startY);
            dragging = true;
        }
    }
    DragListener listener = new DragListener();
    circle.setOnMousePressed(event -> {
        if (event.getButton() == MouseButton.PRIMARY) {
            Point2D pt = circle.localToParent(event.getX(), event.getY());
            listener.startX = circle.getCenterX() - pt.getX();
            listener.startY = circle.getCenterY() - pt.getY();
        }
    });
    circle.setOnMouseReleased(event -> {
        if (event.getButton() == MouseButton.PRIMARY) {
            event.consume();
            if (listener.dragging) {
                listener.dragging = false;
            } else {
                if (constructionPath == null) {
                    // start new path
                    MoveTo move = new MoveTo();
                    move.xProperty().bind(circle.centerXProperty());
                    move.yProperty().bind(circle.centerYProperty());
                    constructionPath = new Path(move);
                    constructionPath.setStrokeWidth(2.5);
                    constructionPath.setOnMouseReleased(evt2 -> {
                        evt2.consume();
                        Path p = (Path) evt2.getSource();
                        p.setStroke(nextColor.get(p.getStroke()));
                    });
                    canvas.getChildren().add(0, constructionPath);
                } else {
                    // end path
                    LineTo line = new LineTo();
                    constructionPath.getElements().add(line);
                    line.xProperty().bind(circle.centerXProperty());
                    line.yProperty().bind(circle.centerYProperty());
                    constructionPath = null;
                }
            }
        }
    });
    circle.setOnMouseDragged(listener);

    canvas.getChildren().add(circle);
}
Pane canvas = new Pane();
canvas.setOnMouseReleased(evt -> {
    if (evt.getButton() == MouseButton.PRIMARY) {
        if (constructionPath == null) {
            // create Circle
            createCircle(evt, canvas);
        } else {
            // add line to path
            LineTo line = new LineTo(evt.getX(), evt.getY());
            constructionPath.getElements().add(line);
        }
    }
});

canvas.setPrefSize(500, 500);

Note: It's easy to miss with clicks on paths. If you want to increase the area the user can click you should do custom checks in the mouseReleased event handler of the canvas Pane.

Upvotes: 2

Related Questions