Add/Remove by mouse click

2019-09-01 09:52发布

I wrote this program which enables the user to add and remove circles in a rectangle, It adds when the user left clicked and removed when he/she right clicked, although its adding works correctly but its removing doesn't work good, for example: when I add four circles and try to remove all of them, some of them doesn't remove and I don't know why,and I'm confused. help please.

public class BoundingRectangle extends Application {
@Override
public void start(Stage primaryStage) {
    Pane pane = new Pane();
    ArrayList<Circle> list = new ArrayList<>();

    Rectangle rectangle1 = new Rectangle(10, 10, 175, 80);
    rectangle1.setStroke(Color.BLACK);
    rectangle1.setFill(Color.WHITE);
    Rectangle rectangle2 = new Rectangle(250, 75, 300, 200);
    rectangle2.setStroke(Color.BLACK);
    rectangle2.setFill(Color.WHITE);

    Text text = new Text(20, 33, "INSTRUCTION\n" +
            "Add: Left Click\nRemove: Right Click");

    pane.setOnMouseClicked(e -> {
        if (e.getButton() == MouseButton.PRIMARY) {
            Circle circle = new Circle(e.getX(), e.getY(), 10);
            list.add(circle);
            circle.setStroke(Color.BLACK);
            circle.setFill(Color.WHITE);

           if (circle.getCenterX() - rectangle2.getX() < 10) {
                circle.setCenterX(rectangle2.getX() + 10);
            } 
           else if (circle.getCenterY() - rectangle2.getY() < 10) {
                circle.setCenterY(rectangle2.getY() + 10);
            } 
           else if (rectangle2.getX() + rectangle2.getWidth() -
                    circle.getCenterX() < 10) {
                circle.setCenterX(rectangle2.getX() +  rectangle2.getWidth()  - 10);
            } 
           else if (rectangle2.getY() + rectangle2.getHeight() -
                    circle.getCenterY() < 10) {
                circle.setCenterY(rectangle2.getY() + rectangle2.getHeight() - 10);
            }
                pane.getChildren().add(circle);
        }

        else if (e.getButton() == MouseButton.SECONDARY) {
                for (int i = 0; i < list.size(); i++) {
                    if (list.get(i).contains(e.getX(), e.getY())) {
                        pane.getChildren().remove(list.get(i));
                        list.remove(i);
                        break;
                    }
                }
            }

        });
        pane.getChildren().addAll(rectangle1, rectangle2, text);

        Scene scene = new Scene(pane, 600, 300);
        primaryStage.setScene(scene);
        primaryStage.setTitle("BoundingRectangle");
        primaryStage.show();
    }
}

1条回答
手持菜刀,她持情操
2楼-- · 2019-09-01 10:41

I think this looks like a bug: if you resize the window after a right-click fails, the repaint forced by the resize removes the circle. Some simple debugging shows that the circles are removed from the pane's child list when they should be (so it is a repaint issue).

As a workaround, replace the second rectangle with a pane. Here is the code with a direct replacement and no other changes: you can actually refactor this a lot to simplify it (registering the mouse listener with the second pane instead of the first for adding, and registering mouse listeners with each of the circle for removing, for example):

import java.util.ArrayList;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.input.MouseButton;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Text;
import javafx.stage.Stage;

public class BoundingRectangle extends Application {
    @Override
    public void start(Stage primaryStage) {
        Pane pane = new Pane();
        ArrayList<Circle> list = new ArrayList<>();

        Rectangle rectangle1 = new Rectangle(10, 10, 175, 80);
        rectangle1.setStroke(Color.BLACK);
        rectangle1.setFill(Color.WHITE);
        Pane rectangle2 = new Pane();
        rectangle2.relocate(250, 75);
        rectangle2.setPrefSize(300,  200);
        rectangle2.setStyle("-fx-border-color: black;");

        Text text = new Text(20, 33, "INSTRUCTION\n"
                + "Add: Left Click\nRemove: Right Click");

        pane.setOnMouseClicked(e -> {
            if (e.getButton() == MouseButton.PRIMARY) {
                Circle circle = new Circle(e.getX(), e.getY(), 10);
                list.add(circle);
                circle.setStroke(Color.BLACK);
                circle.setFill(Color.WHITE);

                if (circle.getCenterX() - rectangle2.getBoundsInParent().getMinX() < 10) {
                    circle.setCenterX(rectangle2.getBoundsInParent().getMinX() + 10);
                } else if (circle.getCenterY() - rectangle2.getBoundsInParent().getMinY() < 10) {
                    circle.setCenterY(rectangle2.getBoundsInParent().getMinY() + 10);
                } else if (rectangle2.getBoundsInParent().getMaxX()
                        - circle.getCenterX() < 10) {
                    circle.setCenterX(rectangle2.getBoundsInParent().getMaxX() - 10);
                } else if (rectangle2.getBoundsInParent().getMaxY()
                        - circle.getCenterY() < 10) {
                    circle.setCenterY(rectangle2.getBoundsInParent().getMaxY() - 10);
                }
                pane.getChildren().add(circle);
            }

            else if (e.getButton() == MouseButton.SECONDARY) {
                for (int i = 0; i < list.size(); i++) {
                    if (list.get(i).contains(e.getX(), e.getY())) {
                        pane.getChildren().remove(list.get(i));
                        list.remove(i);
                        break;
                    }
                }
            }

        });
        pane.getChildren().addAll(rectangle1, rectangle2, text);

        Scene scene = new Scene(pane, 600, 300);
        primaryStage.setScene(scene);
        primaryStage.setTitle("BoundingRectangle");
        primaryStage.show();
    }

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

Here's the refactored version. Since rectangle2 is now a Pane, you can add the circles directly to it, and not have to worry about adjusting their position. The right-click is handled on the circles themselves, so there's no need for code to check if the click was on a circle, and because of that, there's no need for the separate list of circles (though your real application may need that for other reasons).

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.input.MouseButton;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Text;
import javafx.stage.Stage;

public class BoundingRectangle extends Application {
    @Override
    public void start(Stage primaryStage) {
        Pane pane = new Pane();

        Rectangle rectangle1 = new Rectangle(10, 10, 175, 80);
        rectangle1.setStroke(Color.BLACK);
        rectangle1.setFill(Color.WHITE);

        Pane rectangle2 = new Pane();
        rectangle2.relocate(250, 75);
        rectangle2.setPrefSize(300,  200);
        rectangle2.setStyle("-fx-border-color: black;");

        Text text = new Text(20, 33, "INSTRUCTION\n"
                + "Add: Left Click\nRemove: Right Click");

        rectangle2.setOnMouseClicked(e -> {
            if (e.getButton() == MouseButton.PRIMARY) {
                Circle circle = new Circle(e.getX(), e.getY(), 10);

                circle.setOnMouseClicked(evt -> {
                    if (evt.getButton() == MouseButton.SECONDARY) {
                        rectangle2.getChildren().remove(circle);
                    }
                });

                circle.setStroke(Color.BLACK);
                circle.setFill(Color.WHITE);

                rectangle2.getChildren().add(circle);
            }


        });
        pane.getChildren().addAll(rectangle1, rectangle2, text);

        Scene scene = new Scene(pane, 600, 300);
        primaryStage.setScene(scene);
        primaryStage.setTitle("BoundingRectangle");
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}
查看更多
登录 后发表回答