2

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.

Gilian Joosen
  • 486
  • 3
  • 21

2 Answers2

4

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;
    }
}
jewelsea
  • 150,031
  • 14
  • 366
  • 406
3

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.

Hami Torun
  • 543
  • 4
  • 6
  • Hi I tried your example but its not working. Either I have the arc aligned in top left of Anchor pane after setting the anchors to 0.0 or it is misplaced totaly. Can you please show some fxml examle on how to achive correct stacking of shapes with arc? – Zavael Nov 28 '15 at 22:48
  • Sorry for the late reply. Here is a [link](http://pastebin.com/GxMBhx7j) to a fxml, created with Scene Builder. Hope it will be helpful. – Hami Torun Dec 03 '15 at 17:15
  • thank you, will look at it, but in meantime I already figure it out that I only need to dynamicaly assign the layoutX to the arc - it is some sort of padding and it has to be different if the arc is lower than 90 degree, different if the arc is 90-180 degree, and if it is bigger etc – Zavael Dec 07 '15 at 14:56
  • I got it working with the AnchorPane. Tried the Group suggestion above without any luck. – David B. Williams Aug 11 '21 at 22:48