在窗格中显示形状的 ArrayList (JavaFX)

Display ArrayList of shapes in pane (JavaFX)

我正在编写一个代码,该程序让用户根据他们点击的位置在屏幕上创建圆圈。我尝试的是将 create new circle 方法放在第一个事件处理程序中,但它所做的只是给我带来了问题。截至目前,我正在尝试以不同的方式解决这个问题。我现在使用 ArrayList 将所有形状组合在一起并将它们显示在窗格中。但是当我 运行 代码时圆圈没有显示。

这是我的代码:

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.scene.shape.Line; 
import javafx.stage.Stage;
    
import java.util.ArrayList;


public class Main extends Application {

    private Pane root;
    private Circle circle;
    private Line line;
    private boolean isClicked = false;
    private ArrayList<Circle> circleList;


    @Override
    public void start(Stage primaryStage) {
        root = new Pane();

        circle = new Circle();
        line = new Line();

         circleList = new ArrayList<Circle>();

        root.getChildren().addAll(line);

        //root.getChildren().addAll(circle); //when this is uncommented the program runs just fine but there is only one circle there at a time

        root.getChildren().addAll(circleList); //I feel like the problem could be here?


        root.setOnMousePressed(new mouseClick());
        root.setOnMouseMoved(new moveMouse());

        Scene scene = new Scene(root, 600, 600);

        primaryStage.setTitle("blank");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    private double getRadius(double pointOnRadiusX, double pointOnRadiusY, double circleCenterX, double circleCenterY) {
        return Math.sqrt(Math.pow(Math.abs(pointOnRadiusX) - Math.abs(circleCenterX), 2) + Math.pow(Math.abs(pointOnRadiusY) - Math.abs(circleCenterY), 2));
    }

    private class mouseClick implements EventHandler<MouseEvent> {


        @Override
        public void handle(MouseEvent e) {



            if (!isClicked) {
                if(e.getEventType() == MouseEvent.MOUSE_PRESSED){


                    circle.setRadius(0);
                    circle.setCenterX(e.getSceneX());
                    circle.setCenterY(e.getSceneY());
                    circle.setStroke(Color.RED);
                    circle.setFill(Color.TRANSPARENT);

                    line.setStartX(e.getSceneX());
                    line.setStartY(e.getSceneY());
                    line.setStroke(Color.RED);
                    isClicked = true;

                    circleList.add(circle);

                }

            }

            else {

                circle.setRadius(getRadius(e.getSceneX(),e.getSceneY(),circle.getCenterX(), circle.getCenterY()));

                circle.setStroke(Color.GREEN);
                line.setStroke(Color.TRANSPARENT);

                isClicked = false;
            }

        }
    }

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

                    circle.setRadius(getRadius(e.getSceneX(),e.getSceneY(),circle.getCenterX(), circle.getCenterY()));

                    line.setEndX(e.getSceneX());
                    line.setEndY(e.getSceneY());


                }
            }
        }
    }


    public static void main(String[] args) {

        Application.launch(args);
    } }

执行这段代码时:

root.getChildren().addAll(circleList);

circleList 为空。鉴于您稍后添加到 circleList,我假设您的印象是 addAll 方法以某种方式将两个列表“链接”在一起。它不是。该方法所做的只是从一个列表中复制所有元素并将它们附加到另一个列表中。请注意,“复制”并不是说每个元素都是重复的;添加到一个列表中的元素与给定列表中的实例相同。但列表本身保持独立。

您还必须确保不要将相同的 Circle 实例多次添加到 root。一个Node最多只能在场景图中出现一次。当开始添加新圈子的过程时,您应该创建一个新的 Circle 对象。如果您计划显示多行,那么您的 Line 也是如此。

这是一个工作示例(没有你的 Line):

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

public class App extends Application {

  private Pane root;
  private Circle circle;

  @Override
  public void start(Stage primaryStage) {
    root = new Pane();
    root.setOnMousePressed(this::handleMousePressed);
    root.setOnMouseMoved(this::handleMouseMoved);
    primaryStage.setScene(new Scene(root, 1000.0, 650.0));
    primaryStage.show();
  }

  private void handleMousePressed(MouseEvent e) {
    if (e.getButton() == MouseButton.PRIMARY && e.getClickCount() == 1) {
      if (circle == null) {
        // start drawing a new circle
        circle = new Circle(e.getX(), e.getY(), 0.0, Color.TRANSPARENT);
        circle.setStroke(Color.RED);
        circle.setStrokeWidth(2.0);
        root.getChildren().add(circle);
      } else {
        // "lock" the circle in place
        circle.setStroke(Color.GREEN);
        circle = null;
      }
    }
  }

  private void handleMouseMoved(MouseEvent e) {
    // if 'circle' is null then there's no circle being drawn
    if (circle != null) {
      double x1 = circle.getCenterX();
      double y1 = circle.getCenterY();
      double x2 = e.getX();
      double y2 = e.getY();
      double r = Math.sqrt(Math.pow(x2 - x1, 2.0) + Math.pow(y2 - y1, 2.0));
      circle.setRadius(r);
    }
  }
}

注意我使用私有方法和方法引用来实现鼠标处理程序。这样更简洁,但在行为上与您的内部 类.

相同

另请注意,我在计算半径时没有使用 Math.abs。使用 abs 实际上是错误的,并且会给您错误的结果 (|x2| - |x1| != x2 - x1)。例如,如果您有 -3 - 2 怎么办?这给你 |-3| - |2| = 1-3 - 2 = -5.

不同