xn139
xn139

Reputation: 395

Circle not visible as I drag the mouse in JavaFX

I'm creating a small paint program in JavaFX and have got a circle creation tool. At the moment, I can draw the circle properly, but unlike my other tools I can't see the circle as it's being created (i.e. as I'm dragging my mouse). It is only when I release the mouse that I see the circle (drawn with the correct dimensions). I tried adding in a strokeOval() method as I dragged, but it creates a strange "teardrop" like circle. I have tried everything - can anyone help?

Here's my code:

public CircleController(Canvas canvas, Scene mainScene, BorderPane borderPane) {

    this.borderPane = borderPane;
    this.mainScene = mainScene;
    this.graphicsContext = canvas.getGraphicsContext2D();

    circle = new Circle();
    circle.setStrokeWidth(1.0);
    circle.setFill(Color.WHITE);
    circle.setStroke(Color.BLACK);

    mousePressed = event -> {
        startingPosX = event.getX();
        startingPosY = event.getY();
        borderPane.getChildren().add(circle);

    };

    mouseReleased = event -> {
        borderPane.getChildren().remove(circle);
        double width = Math.abs(event.getX() - startingPosX);
        double height = Math.abs(event.getY() - startingPosY);
        graphicsContext.strokeOval(startingPosX, startingPosY, width, height);
        graphicsContext.setStroke(Color.BLACK);
        removeListeners();
    };

    mouseDragged = event -> {
        circle.setCenterX(event.getX() - startingPosX);
        circle.setCenterY(event.getY() - startingPosY);

    };
}

This above code creates the circle correctly, but cannot be seen until I release the mouse. I apply the above EventHandlers to my scene:

@Override
public void handle(ActionEvent event) {
    mainScene.setOnMousePressed(mousePressed);
    mainScene.setOnMouseDragged(mouseDragged);
    mainScene.setOnMouseReleased(mouseReleased);
}

Can anyone help please?

Upvotes: 1

Views: 1063

Answers (1)

fabian
fabian

Reputation: 82461

What you're drawing a oval not a circle. The Circle class cannot appropriately handle this. You need Ellipse. Furthermore note that dragging up/left from the start of the gesture results in weird behavior of the oval, since it's always drawn in the first quadrant of the coordinate system with origin at the start of the drag gesture.

The following code should allow drawing the oval in every quadrant and also use a Ellipse as "preview":

// TODO: replace circle field with ellipse field of type Ellipse
ellipse = new Ellipse();
ellipse.setStrokeWidth(1.0);
ellipse.setFill(Color.TRANSPARENT);
ellipse.setStroke(Color.BLACK);

mousePressed = event -> {
    startingPosX = event.getX();
    startingPosY = event.getY();
    ellipse.setCenterX(startingPosX);
    ellipse.setCenterY(startingPosY);
    ellipse.setRadiusX(0);
    ellipse.setRadiusY(0);
    borderPane.getChildren().add(ellipse);
};

mouseReleased = event -> {
    borderPane.getChildren().remove(ellipse);
    double width = Math.abs(event.getX() - startingPosX);
    double height = Math.abs(event.getY() - startingPosY);
    graphicsContext.setStroke(Color.BLACK);
    graphicsContext.strokeOval(Math.min(startingPosX, event.getX()), Math.min(startingPosY, event.getY()), width, height);
    removeListeners();
};

mouseDragged = event -> {
    ellipse.setCenterX((event.getX() + startingPosX) / 2);
    ellipse.setCenterY((event.getY() + startingPosY) / 2);
    ellipse.setRadiusX(Math.abs((event.getX() - startingPosX) / 2));
    ellipse.setRadiusY(Math.abs((event.getY() - startingPosY) / 2));
};

Upvotes: 2

Related Questions