Search code examples
javajavafxgeometryevent-handlingmouseevent

Draw circle with mouse click points (JavaFX)


Before you read on this is for my homework assignment so the requirements for the questions will be specific.

I am writing a program that clicks draws a line on the canvas and displays the circle as shown from where you dragged your mouse. What my code does is that it clicks to start a point and wherever you drag the mouse and let go is the circle. However, I want my circle to start with a point selected (mouse clicked and release) then drag the mouse and the circle to where it is, and when the mouse is clicked again it will secure the circle on the canvas. What I have tried is to make two mouse event listeners, one for the initialization of the circle and one to end the circle's radius. But that didn't work. I've also tried to put the getX() and getY() into the main method but that also didn't work.

This is my code

import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
import javafx.scene.shape.Line;


public class Main extends Application {
    private Circle circle;

    @Override
    public void start(Stage primaryStage) {
        Pane root = new Pane();
        circle = new Circle(-10,-10,-10);
        circle.setFill(Color.TRANSPARENT);
        circle.setStroke(Color.BLACK);

        root.getChildren().add(circle);

        root.setOnMousePressed(new MousePressEventHandler());
        root.setOnMouseDragged(new MouseDragEventHandler());

        Scene scene = new Scene(root, 600, 600);
        primaryStage.setTitle("blank");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    private class MousePressEventHandler implements EventHandler<MouseEvent> {
        @Override
        public void handle(MouseEvent e) {

            circle.setCenterX(e.getX());
            circle.setCenterY(e.getY());


            circle.setRadius(e.getX());
            circle.setRadius(e.getY());

        }
    }

    private class MouseDragEventHandler implements EventHandler<MouseEvent> {
        @Override
        public void handle(MouseEvent e) {
            circle.setRadius(e.getX());
            circle.setRadius(e.getY());

        }
    }


    public static void main(String[] args) {

        Application.launch(args);
    }
}

Solution

  • Here is how I would do it, expanding on my comment from earlier. I tested this, and it works according to your description. I handle my events a little differently, only because I like being able to add my events to particular instances of a scene. You should be able to implement it your way no problem.

    import javafx.application.Application;
    import javafx.scene.Group;
    import javafx.scene.Scene;
    import javafx.scene.paint.Color;
    import javafx.scene.shape.Circle;
    import javafx.stage.Stage;
    
    public class Test extends Application {
    
        private Circle circle;
        private boolean firstClick = true;
        private double centerX, centerY;
    
        public static void main(String[] args) {
            launch(args);
        }
    
        @Override
        public void start(Stage primaryStage) throws Exception {
            Group root = new Group();
        
            circle = new Circle();
            circle.setFill(Color.TRANSPARENT);
            circle.setStroke(Color.BLACK);
        
            root.getChildren().add(circle);        
    
            Scene scene = new Scene(root, 600, 600);
            setHandlers(scene);
        
            primaryStage.setTitle("blank");
            primaryStage.setScene(scene);
            primaryStage.show();
        }
    
        public void setHandlers(Scene scene) {
            scene.setOnMouseClicked(
                e -> {
                    // first instance of clicking the mouse will set the center of the circle
                    if (firstClick) { 
                        // you need to keep references of the your circle center when moving the mouse
                        centerX = e.getX();
                        centerY = e.getY();
                        // sets the center
                        circle.setCenterX(centerX);
                        circle.setCenterY(centerY);
                        // sets next "stage" of drawing your circle
                        firstClick = false;
                    // on second click will reset the process by setting firstClick to true
                    } else {
                        firstClick = true;
                    }
                }
            );
        
            scene.setOnMouseMoved(
                e -> {
                    // will only evaluate on the first instance of a click
                    if (!firstClick) {
                        // Distance formula between center of circle and mouse pointer
                        double c = Math.sqrt(Math.pow(centerX - e.getX(), 2) + 
                                         Math.pow(centerY - e.getY(), 2));
                        circle.setRadius(c);
                    }
                }
            );
        }
    }