Search code examples
javajavafxjavafx-8java-canvas

JavaFX deleting last drawn object from canvas


Introduction:

I have created a canvas and my objective is creating circles at the place you click on the canvas. But I also want to be able to delete the circles I have drawn or at least the last drawn one. Redrawing at the same place where the circle is with background color is not a good solution. Because if there are other things under the circle they'll be deleted as well. For instance in this application 2 circles might have intersection and when you try to delete the 2nd circle those intersection points will be empty which would mean erasing some part of the first circle too. So I thought of creating 2nd canvas. And every time I click somewhere on the canvas before drawing the circle I would assign main canvas to backup canvas. And when I want to delete the last drawn object I could load the backup canvas.

Now I tried to do what I explained on the above and couldn't make it work as I intend it to do. In fact I even saw some strange (at least for me) behaviors on other things.

What I have done is basically creating 2 canvas at the same size.

public class Main extends Application {
    double ldx, ldy, diameter;
    Canvas lastCanvas = new Canvas(800,600);
    Canvas pane1 = new Canvas(800,600);

    @Override
    public void start(Stage primaryStage) throws Exception{
        System.out.println("Hello");
        HBox root = new HBox();

        GraphicsContext gc = pane1.getGraphicsContext2D();
        pane1.setOnMouseClicked(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
                // Draw circle around x,y
                lastCanvas = pane1;
                diameter = 25.0;
                ldx = event.getSceneX() - ( diameter/2 );
                ldy = event.getSceneY() - ( diameter/2 );
                gc.strokeOval(ldx, ldy, diameter, diameter);
                System.out.println("Clicked");
            }
        });
        VBox pane2 = new VBox(10);
        pane2.setPrefSize(224,600);
        Button button1 = new Button("Clear Last Drawn");
        button1.setOnMouseClicked(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
                pane1 = lastCanvas;
                System.out.println("Last canvas loaded");
            }
        });
        pane2.getChildren().addAll(button1);
        pane1.setStyle("-fx-background-color: #224488");
        pane2.setStyle("-fx-background-color: #224488");
        root.getChildren().addAll(pane1, pane2);
        Scene scene1 = new Scene(root, 1024, 600);
        primaryStage.setScene(scene1);
        primaryStage.setTitle("Mouse Clicker");
        primaryStage.show();

    }
}

Expected behavior is that every time I click on the button it'll load the lastCanvas which is the canvas before I drawn the last object. But it doesn't. I tried something like this inside button1's mouseevent

root.getChildren().removeAll();
root.getChildren().addAll(lastCanvas, pane2);

Which generates error on the console every time you click button. Another problem is that I tried to create 2nd scene.

HBox root2 = new HBox();
root2.getChildren().addAll(lastCanvas, pane2);

Doing this suprisingly deletes everything on the pane2 although I don't use root2 anywhere. All I do here is creating a new HBox and adding pane2 into that hbox too. Why doing this removes pane2 from my primaryStage instead leaves white space?

Additionally if you have other recommendation for removing the last object drawn on the canvas -once or until canvas is fully empty- you can also tell me that instead of trying to solve what I did wrong on the code above.


Solution

  • Without analyzing the problem, I propose the following solution using your code as a base

        private final double diameter = 25;
        private final LinkedList<Point2D> centers = new LinkedList<>();
        private final Canvas pane1 = new Canvas(800, 600);
    
        @Override
        public void start(Stage primaryStage) throws Exception
        {
            System.out.println("Hello");
            HBox root = new HBox();
    
            pane1.setOnMouseClicked((MouseEvent event) ->
            {
                centers.add(new Point2D(event.getSceneX(), event.getSceneY()));
                render();
                System.out.println("Clicked");
            });
            VBox pane2 = new VBox(10);
            pane2.setPrefSize(224, 600);
            Button button1 = new Button("Clear Last Drawn");
            button1.setOnMouseClicked((MouseEvent event) ->
            {
                if (!centers.isEmpty())
                {
                    centers.removeLast();
                    render();
                    System.out.println("Last canvas loaded");
                }
            });
            pane2.getChildren().addAll(button1);
            pane1.setStyle("-fx-background-color: #224488");
            pane2.setStyle("-fx-background-color: #224488");
            root.getChildren().addAll(pane1, pane2);
            Scene scene1 = new Scene(root, 1024, 600);
            primaryStage.setScene(scene1);
            primaryStage.setTitle("Mouse Clicker Project (Berk YATKIN)");
            primaryStage.show();
    
        }
    
        private void render()
        {
            pane1.getGraphicsContext2D().clearRect(0, 0, pane1.getWidth(), pane1.getHeight());
            centers.forEach((p) ->
            {
                pane1.getGraphicsContext2D().strokeOval(
                        p.getX() - (diameter / 2),
                        p.getY() - (diameter / 2),
                        diameter,
                        diameter);
            });
        }