我只希望单击Arc中彼此重叠的StackPane的边界。当前,我的下面代码也选择了Arc的填充,并且当我单击下图中的点p3时,无法启动MOUSE_CLICKEDarc1事件。我期望的结果和当前结果的解释也在下面。

java - javafx代码,仅在MOUSE_CLICKED事件上选择圆弧的边界-LMLPHP

  • 当用户单击p1时,代码将按预期工作,并显示“arc2”
  • 当用户单击p2时,代码将打印“arc2”,而预期的操作是不执行任何操作
  • 当用户单击p3时,代码将打印“arc2”,而预期的操作是打印“arc1”

    这是因为即使填充是透明的并且Arc2设置为Arc1PickOnBounds的填充区域还是在false之前拾取的。我正在尝试找到一种方法来使填充区域不被拾取。失败的话,我想触发两个Arc的事件处理程序,以便我自己处理行为。

    代表我的问题的代码:
    import javafx.application.Application;
    import javafx.scene.Scene;
    import javafx.scene.layout.StackPane;
    import javafx.scene.paint.Color;
    import javafx.scene.shape.Arc;
    import javafx.scene.shape.ArcType;
    import javafx.stage.Stage;
    
    public class Example extends Application {
    
        @Override
        public void start(Stage primaryStage) {
            Arc arc1 = new Arc(100, 100, 100, 100, 90, 90);
            Arc arc2 = new Arc(0, 100, 100, 100, 0, 90);
    
            arc1.setStroke(Color.BLACK);
            arc2.setStroke(Color.BLACK);
            arc1.setFill(Color.TRANSPARENT);
            arc2.setFill(Color.TRANSPARENT);
            arc1.setStrokeWidth(10);
            arc2.setStrokeWidth(10);
            arc1.setType(ArcType.OPEN);
            arc2.setType(ArcType.OPEN);
    
            arc1.setPickOnBounds(false);
            arc2.setPickOnBounds(false);
    
            arc1.setOnMouseClicked(event -> System.out.println("arc1"));
            arc2.setOnMouseClicked(event -> System.out.println("arc2"));
    
          StackPane root = new StackPane();
          root.getChildren().add(arc1);
          root.getChildren().add(arc2);
    
          Scene scene = new Scene(root, 300, 250);
    
          primaryStage.setTitle("Picking Issues");
          primaryStage.setScene(scene);
          primaryStage.show();
        }
    
        public static void main(String[] args) {
            launch(args);
        }
    }
    

    编辑:

    c0der's的帮助下,我实现了预期的行为,如下所示:
        import javafx.application.Application;
        import javafx.geometry.Point2D;
        import javafx.scene.Node;
        import javafx.scene.Scene;
        import javafx.scene.layout.StackPane;
        import javafx.scene.paint.Color;
        import javafx.scene.shape.Arc;
        import javafx.scene.shape.ArcType;
        import javafx.stage.Stage;
    
        public class Example extends Application {
    
            private  Arc arc1, arc2;
            private StackPane root;
    
          @Override
          public void start(Stage primaryStage) {
              arc1 = getArc(200, 200, 200, 200, 90, 90, "arc1");
              arc2 = getArc(0, 200, 200, 200, 0, 90, "arc2");
              root = new StackPane(arc1, arc2);
              root.setOnMouseClicked(event -> onStackPaneClick(event.getX(), event.getY()));
              Scene scene = new Scene(root, 200, 200);
              primaryStage.setScene(scene);
              primaryStage.show();
          }
    
          private Arc getArc(double x, double y,  double radiusX, double radiusY, double startAngle, double endAngle, String userData){
              Arc arc = new Arc(x,y, radiusX,radiusY,startAngle, endAngle);
              arc.setStroke(Color.BLACK);
              arc.setFill(Color.TRANSPARENT);
              arc.setStrokeWidth(10);
              arc.setType(ArcType.OPEN);
              arc.setPickOnBounds(false);
              arc.setUserData(userData);
              return arc;
          }
    
          private void onStackPaneClick(double x, double y) {
            for (Node itNode : root.getChildren()) {
                if (itNode.contains(new Point2D(x, y))) {
                    if (itNode instanceof Arc) {
                        Arc itArc = (Arc) itNode;
                        double centerDistance = Math.sqrt(
                                (x - itArc.getCenterX()) * (x - itArc.getCenterX()) +
                                (y - itArc.getCenterY()) * (y - itArc.getCenterY()));
                        if (centerDistance >= itArc.getRadiusX() - itArc.getStrokeWidth() / 2) {
                            System.out.println(itArc.getUserData());
                            break;
                        }
                    }
                }
            }
          }
    
          public static void main(String[] args) {
              launch(args);
          }
        }
    

    但是,由于最初的问题需要,该问题在技术上仍然没有答案。
  • 一种从点击事件或
  • 中排除“填充”区域的方法
  • 一种方法,当一个单击的点包含在多个形状中时,将触发所有包含该单击的点的形状的事件处理程序

    最佳答案

    只需检查Node contains是否为点击点:

    import javafx.application.Application;
    import javafx.geometry.Point2D;
    import javafx.scene.Scene;
    import javafx.scene.layout.StackPane;
    import javafx.scene.paint.Color;
    import javafx.scene.shape.Arc;
    import javafx.scene.shape.ArcType;
    import javafx.stage.Stage;
    
    public class FxmlTest extends Application {
    
        private  Arc arc1, arc2;
    
        @Override
        public void start(Stage primaryStage) {
            arc1 = getArc(100, 100, 100, 100, 90, 90);
            arc2 = getArc(0, 100, 100, 100, 0, 90);
            StackPane root = new StackPane(arc1, arc2);
            Scene scene = new Scene(root, 300, 250);
            primaryStage.setScene(scene);
            primaryStage.show();
        }
    
        private Arc getArc(double x, double y,  double radiusX, double radiusY, double startAngle, double endAngle){
            Arc arc = new Arc(x,y, radiusX,radiusY,startAngle, endAngle);
            arc.setStroke(Color.BLACK);
            arc.setFill(Color.TRANSPARENT);
            arc.setStrokeWidth(10);
            arc.setType(ArcType.OPEN);
            arc.setPickOnBounds(false);
            arc.setOnMouseClicked(event -> checkClickedPoint(event.getX(), event.getY()));
            return arc;
        }
        private void checkClickedPoint(double x, double y) {
            Point2D clickedPoint = new Point2D(x, y);
            if(arc1.contains(clickedPoint)) {System.out.println("arc1");}
            if(arc2.contains(clickedPoint)) {System.out.println("arc2");}
        }
    
        public static void main(String[] args) {
            launch(null);
        }
    }
    

    编辑:
    为避免弧形填充区域(图像中的黄色区域)发生鼠标单击事件

    java - javafx代码,仅在MOUSE_CLICKED事件上选择圆弧的边界-LMLPHP

    您只能构建轮廓的形状,而无需填充区域。
    我们将其称为arc1中的弧。
    构造第二个弧,arc2,它较小并包含在arc1中。arc2的构造使其覆盖黄色区域。
    arc2减去arc1会返回一个形状,该形状是arc1的轮廓:
    class ArcContour {
    
        private final Shape arcContour;
        private static final double STROKE = 10;
    
        public ArcContour(double x, double y, double radiusX, double radiusY, double startAngle, double length) {
    
            Arc arc1 = new Arc(x,y, radiusX,radiusY,startAngle, length);
            arc1.setStroke(Color.BLACK);
            arc1.setStrokeWidth(STROKE);
            arc1.setStrokeType(StrokeType.INSIDE);
            arc1.setType(ArcType.OPEN);
            arc1.setPickOnBounds(false);
    
            Arc arc2 = new Arc(x,y, radiusX - STROKE,radiusY - STROKE,startAngle, length);
            arc2.setStrokeType(StrokeType.INSIDE);
            arcContour = Shape.subtract(arc1, arc2);
        }
    
        Shape getShape() {
            return arcContour;
        }
    }
    

    通过以下方式进行测试:
    public class FxmlTest extends Application {
    
        private  Shape shape;
        private static final double RADIUS = 100;
    
        @Override
        public void start(Stage primaryStage) {
    
            shape = new ArcContour(150, 150, RADIUS, RADIUS, 30, 150).getShape();
            shape.setOnMouseClicked(event -> checkClickedPoint(event.getX(), event.getY()));
            StackPane root = new StackPane(shape);
            Scene scene = new Scene(root, 300, 250);
            primaryStage.setScene(scene);
            primaryStage.show();
        }
    
        //this functinality can be refactored to ArcContour
        private void checkClickedPoint(double x, double y) {
            if( shape.contains(new Point2D(x, y))) {System.out.println("Arc clicked");}
        }
    
        public static void main(String[] args) {
            launch(null);
        }
    }
    

  • 09-05 08:57