JavaFX center an resizable arc in a borderpane

2.5k views Asked by At

I have a question. I am creating an application where an Arc length changes and I want that arc inside a borderpane, but when i change the length of the Arc it will get centered, so it doesn't look like a circle that's getting filled. Actually what i need is an arc and calculate it's position (the center of the borderpane) by it's maximum length (360). Can someone help me with this problem? Thank you very much.

2

There are 2 answers

0
jewelsea On BEST ANSWER

Create a Group. Place a rectangle in the group which is the size of a full circle (e.g. the rectangle's height and width is set to the circle's diameter), then add the arc to the group, with the arc layout position set to the circle's radius. Place the Group in a StackPane so that the fixed size Group will be centered within a resizable Region. Place the StackPane in the center of your BorderPane. Set the minimum size of the StackPane to zero so that it can be sized smaller than the Group, keeping the Group centered and clipped within it's visible bounds. Add some controls to the bottom of the BorderPane so that you can control the length of the arc dynamically.

arcimage

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.*;
import javafx.scene.control.Slider;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.*;
import javafx.stage.Stage;

public class ArcControl extends Application {
    @Override
    public void start(Stage stage) throws Exception {
        CenteredArc centeredArc = new CenteredArc();
        ArcControls arcControls = new ArcControls(centeredArc.getArc());

        BorderPane layout = new BorderPane();
        layout.setCenter(centeredArc.getArcPane());
        layout.setBottom(arcControls.getControlPane());

        stage.setScene(new Scene(layout));
        stage.show();
    }

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

class CenteredArc {
    private static final double INSET = 10;

    private static final double ARC_RADIUS = 100;
    private static final double INITIAL_ARC_LENGTH  = 60;
    private static final double ARC_STROKE_WIDTH = 10;
    private static final double ARC_REGION_SIZE =
            ARC_RADIUS * 2 + ARC_STROKE_WIDTH + INSET * 2;

    private final Arc arc;
    private final Pane arcPane;

    public CenteredArc() {
        // Create the arc.
        arc = new Arc(
                ARC_REGION_SIZE / 2, ARC_REGION_SIZE / 2,
                ARC_RADIUS, ARC_RADIUS,
                0,
                INITIAL_ARC_LENGTH
        );
        arc.setStrokeWidth(10);
        arc.setStrokeLineCap(StrokeLineCap.ROUND);
        arc.setStroke(Color.FORESTGREEN);
        arc.setFill(Color.POWDERBLUE);

        // Create a background fill on which the arc will be centered.
        // The paint of the background fill can be set to Color.TRANSPARENT
        // if you don't want the fill to be seen.
        final double fillSize = ARC_RADIUS * 2 + arc.getStrokeWidth() + INSET * 2;
        Rectangle fill = new Rectangle(fillSize, fillSize, Color.PINK);

        // Place the fill and the arc in the group.
        // The Group will be a fixed sized matching the fill size.
        Group centeredArcGroup = new Group(fill, arc);

        // place the arc group in a StackPane so it is centered in a resizable region.
        arcPane = new StackPane(centeredArcGroup);
        arcPane.setPadding(new Insets(INSET));
        arcPane.setMinSize(0, 0);
        arcPane.setStyle("-fx-background-color: papayawhip;");
    }

    public Arc getArc() {
        return arc;
    }

    public Pane getArcPane() {
        return arcPane;
    }
}

// helper class which can use a slider to control an arc.
class ArcControls {
    private static final double INSET = 10;

    private final Slider slider;
    private final VBox controlPane;

    public ArcControls(Arc arc) {
        slider = new Slider(0, 360, arc.getLength());
        controlPane = new VBox(
                slider
        );
        controlPane.setPadding(
                new Insets(INSET)
        );
        controlPane.setStyle(
                "-fx-background-color: palegreen;"
        );

        arc.lengthProperty().bind(slider.valueProperty());
    }

    public Slider getSlider() {
        return slider;
    }

    public VBox getControlPane() {
        return controlPane;
    }
}
4
Hami Torun On

Inside BorderPane (or StackPane) the alignment is done according to the bounding box of the shape (top left, center, bottom etc.). Therefore the center point of the arc will move and will not give you the effect you want.

Instead, put the arc inside an AnchorPane (if you want to use BorderPane, put AnchorPane inside a region (left, right, center etc.) of the BorderPane). This will fix the center point of the arc even if you change the arc length and give you the effect of a circle getting filled with the increasing arc length.