JavaFX从画布删除最后绘制的对象

JavaFX从画布删除最后绘制的对象,java,javafx,javafx-8,java-canvas,Java,Javafx,Javafx 8,Java Canvas,导言: 我已经创建了一个画布,我的目标是在你点击画布的地方创建圆圈。但我也希望能够删除我画的圆,或者至少是最后一个画的圆。在具有背景色的圆所在的同一位置重新绘制不是一个好的解决方案。因为如果圆圈下还有其他东西,它们也会被删除。例如,在此应用程序中,两个圆可能有交点,当您尝试删除第二个圆时,这些交点将为空,这意味着也将删除第一个圆的某些部分。所以我想创作第二幅画布。每次我在画圆圈之前单击画布上的某个地方,我都会将主画布指定给备份画布。当我想删除最后绘制的对象时,我可以加载备份画布 现在我试着去做我

导言:

我已经创建了一个画布,我的目标是在你点击画布的地方创建圆圈。但我也希望能够删除我画的圆,或者至少是最后一个画的圆。在具有背景色的圆所在的同一位置重新绘制不是一个好的解决方案。因为如果圆圈下还有其他东西,它们也会被删除。例如,在此应用程序中,两个圆可能有交点,当您尝试删除第二个圆时,这些交点将为空,这意味着也将删除第一个圆的某些部分。所以我想创作第二幅画布。每次我在画圆圈之前单击画布上的某个地方,我都会将主画布指定给备份画布。当我想删除最后绘制的对象时,我可以加载备份画布

现在我试着去做我在上面解释过的事情,却不能按照我的意愿去做。事实上,我甚至看到了一些奇怪的行为,至少对我来说是这样

我所做的基本上是创建两个相同大小的画布

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

    }
}
这会在每次单击按钮时在控制台上生成错误。另一个问题是,我试图创建第二个场景

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

这样做会令人惊讶地删除窗格2上的所有内容,尽管我没有在任何地方使用root2。我在这里所做的就是创建一个新的HBox,并将pane2添加到该HBox中。为什么这样做会从我的primaryStage中删除pane2,而留下空白


此外,如果您有其他建议删除画布上绘制的最后一个对象(一次或直到画布完全空为止),您也可以告诉我,不要试图解决我在上面的代码中犯的错误。

在不分析问题的情况下,我以您的代码为基础,提出以下解决方案

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

在不分析问题的情况下,我使用您的代码作为基础,提出以下解决方案

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

}

这是一个直接使用场景图的解决方案。此示例还可以通过图形选择轻松扩展,以在圆周围移动圆或删除圆。所有不容易用画布实现的事情。

您要求它,所以它在这里:

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

}

这是一个直接使用场景图的解决方案。此示例还可以通过图形选择轻松扩展,以在圆周围移动圆或删除圆。所有使用画布不容易做到的事情。

这样做会令人惊讶地删除窗格2上的所有内容,尽管我没有在任何地方使用root2。我在这里所做的就是创建一个新的HBox并将pane2添加到该HBox中。=>From:如果程序向父节点(包括组、区域等)添加子节点,并且该节点已经是另一父节点的子节点或场景的根节点,则该节点将自动且静默地从其前父节点中移除。每个问题一个问题很好:-这样做会令人惊讶地删除窗格2上的所有内容,尽管我没有在任何地方使用root2。我在这里所做的就是创建一个新的HBox并将pane2添加到该HBox中。=>From:如果程序向父节点(包括组、区域等)添加子节点,并且该节点已经是另一父节点的子节点或场景的根节点,则该节点将自动且静默地从其前父节点中移除。每个问题一个问题很好:-我看到您的实现存储了每个圆,每次它绘制一个圆时,它会清除整个画布,然后再次绘制每个圆。我不确定这是不是一个好的解决方案,但至少它的工作,因为我想要它所以谢谢。顺便说一下,我将get.SceneX和get.SceneY转换为float,因为Point2D函数需要float参数,希望可以这样做。此外,在渲染函数中,它应该是p.x和p.y,而不是p.getX和p.getY。再次感谢您的回复,这对我来说已经足够了。另外,您和我创建鼠标点击事件的方式有什么不同吗?我也可以说IntelliJ的方式,因为整个onMouseClick事件是自动生成的。关于Point2D,我使用“javafx.geometry.Point2D”,我认为您使用的是“com.sun.javafx.geom.Point2D”。至于监听器,我使用lamdas Java 8代替匿名类。最后,您应该以这个例子作为概念证明,场景图可能是一个更好的解决方案,但是使用canvas应该能够重新绘制数十万个圆
每秒几次。我看到您的实现存储每个圆,每次它绘制一个圆时,它会清除整个画布,然后再次绘制每个圆。我不确定这是不是一个好的解决方案,但至少它的工作,因为我想要它所以谢谢。顺便说一下,我将get.SceneX和get.SceneY转换为float,因为Point2D函数需要float参数,希望可以这样做。此外,在渲染函数中,它应该是p.x和p.y,而不是p.getX和p.getY。再次感谢您的回复,这对我来说已经足够了。另外,您和我创建鼠标点击事件的方式有什么不同吗?我也可以说IntelliJ的方式,因为整个onMouseClick事件是自动生成的。关于Point2D,我使用“javafx.geometry.Point2D”,我认为您使用的是“com.sun.javafx.geom.Point2D”。至于监听器,我使用lamdas Java 8代替匿名类。最后,您应该以这个例子作为概念证明,场景图可能是一个更好的解决方案,但是使用canvas应该能够每秒多次重画数十万个圆。谢谢您的回复。我什么都没坚持。我不知道这方面的知识,当我第一次搜索JavaGUI编程时,我看到了两件事:Swing和JavaFX。简单看了一下之后,我发现JavaFX比较新,swing比较旧,所以我想用新的。在JavaFX的文档中,我还看到它展示了如何在画布上绘制对象,并认为我可以使用它。没有看到你提到的场景图。但若你们能用场景图给我写一个,我很乐意检查你们的实现。谢谢,谢谢你的回复。我什么都没坚持。我不知道这方面的知识,当我第一次搜索JavaGUI编程时,我看到了两件事:Swing和JavaFX。简单看了一下之后,我发现JavaFX比较新,swing比较旧,所以我想用新的。在JavaFX的文档中,我还看到它展示了如何在画布上绘制对象,并认为我可以使用它。没有看到你提到的场景图。但若你们能用场景图给我写一个,我很乐意检查你们的实现。谢谢,谢谢你的密码。但是有没有办法过滤graphicsPane中的节点?因为这样它不会擦除最后绘制的圆,而是擦除最后绘制的对象。那么,有没有一种方法可以让graphicPane中只有圈的子对象?当然有。你只需反复浏览列表,找到最后一圈。不是我投了反对票,即使我投了,也不会显示,因为我没有足够的声誉。我不知道那家伙的原因,但这帮了我的忙,谢谢。我找到了获得最后一个圈的方法,我将根据这个圈向你的帖子提交编辑,以防像我这样的初学者想知道怎么做。谢谢你的代码。但是有没有办法过滤graphicsPane中的节点?因为这样它不会擦除最后绘制的圆,而是擦除最后绘制的对象。那么,有没有一种方法可以让graphicPane中只有圈的子对象?当然有。你只需反复浏览列表,找到最后一圈。不是我投了反对票,即使我投了,也不会显示,因为我没有足够的声誉。我不知道那家伙的原因,但这帮了我的忙,谢谢。我找到了获得最后一个圈的方法,我将根据这个圈向你的帖子提交编辑,以防像我这样的初学者想知道如何做。