JavaFX удаляет последний нарисованный объект с холста

Вступление:

Я создал холст, и моя цель - создать круги в том месте, где вы нажимаете на холсте. Но я также хочу иметь возможность удалить нарисованные круги или, по крайней мере, последний нарисованный круг. Перерисовка в том же месте, где круг с цветом фона, не является хорошим решением. Потому что если в круге есть другие вещи, они также будут удалены. Например, в этом приложении 2 круга могут иметь пересечение, и когда вы попытаетесь удалить 2-й круг, эти точки пересечения будут пустыми, что будет означать также удаление некоторой части первого круга. Поэтому я подумал о создании 2-го холста. И каждый раз, когда я щелкаю где-нибудь на холсте, перед тем как нарисовать круг, я назначаю основной холст резервному холсту. И когда я хочу удалить последний нарисованный объект, я могу загрузить резервную копию холста.

Теперь я попытался сделать то, что объяснил выше, и не смог заставить его работать так, как я намеревался. На самом деле я даже видел некоторые странные (по крайней мере для меня) поведения в других вещах.

В основном я создал 2 холста одинакового размера.

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();

    }
}

Ожидаемое поведение заключается в том, что каждый раз, когда я нажимаю на кнопку, он загружает lastCanvas, который является холстом перед тем, как я нарисовал последний объект. Но это не так. Я попробовал что-то вроде этого в mouseevent button1

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

Который генерирует ошибку на консоли каждый раз, когда вы нажимаете кнопку. Другая проблема заключается в том, что я пытался создать 2-ю сцену.

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

Это неожиданно удаляет все на панели 2, хотя я нигде не использую root2. Все, что я делаю здесь, это создание нового HBox и добавление pane2 в этот hbox. Почему при этом удаляется pane2 из моего primaryStage, а не остается пустое пространство?

Кроме того, если у вас есть другие рекомендации по удалению последнего объекта, нарисованного на холсте - или до тех пор, пока холст не станет полностью пустым - вы также можете сказать мне об этом, вместо того чтобы пытаться решить, что я сделал неправильно в приведенном выше коде.

3 ответа

Решение

Не анализируя проблему, я предлагаю следующее решение, используя ваш код в качестве основы

    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);
        });
    }

Вы просили об этом, поэтому вот оно:

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;

public class Main extends Application {
    @Override
    public void start(Stage primaryStage) throws Exception{
        BorderPane root = new BorderPane();

        Pane graphicsPane = new Pane();
        root.setCenter(graphicsPane);

        graphicsPane.setOnMouseClicked(e -> {
            // Draw circle around x,y
            Circle circle = new Circle(e.getX(), e.getY(), 50.0);
            circle.setStroke(Color.RED);
            circle.setStrokeWidth(4.0);
            circle.setFill(null);
            graphicsPane.getChildren().add(circle);
        });

        VBox pane2 = new VBox(10);
        pane2.setPrefWidth(224);
        Button button1 = new Button("Clear Last Drawn");
        button1.setOnAction(e -> {
            int numCircles = graphicsPane.getChildren().size();
            if (numCircles > 0) {
                graphicsPane.getChildren().remove(numCircles - 1);
            }
        });

        pane2.getChildren().addAll(button1);
        root.setRight(pane2);
        graphicsPane.setStyle("-fx-background-color: #aaaaaa");
        pane2.setStyle("-fx-background-color: #224488");
        Scene scene1 = new Scene(root, 1024, 600);
        primaryStage.setScene(scene1);
        primaryStage.setTitle("Mouse Clicker");
        primaryStage.show();

    }

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

}

Это решение с использованием графа сцены напрямую. Этот пример также может быть легко расширен для перемещения окружностей по кругу или удаления круга с помощью графического выделения. Все вещи, которые не легко возможны с холстом.

Также, не анализируя проблему, я сначала задам вопрос, почему вы настаиваете на использовании холста. Граф сцены гораздо больше подходит для такого рода задач. Вы можете добавить (почти) любое количество кругов и удалить столько их, сколько хотите в любом порядке. Что могло быть проще этого?

Другие вопросы по тегам