java - 通过形状传递鼠标单击事件

标签 java javafx

我正在做一个我需要的项目
制作圆圈并使用立方曲线将它们关联起来 如下图所示:
enter image description here

我需要将鼠标单击事件传递到用“ALICEBLUE”着色的立方曲线部分,但仍然能够将鼠标单击事件传递到用“BLACK”着色的线条。

三次曲线代码:

public class transLine extends CubicCurve {

private Polygon polygon;
private Circle to;
private Circle from;
private double arrowHeadTransLength;

public Circle getTo() {
    return to;
}

public void setTo(Circle to) {
    this.to = to;
}

public Circle getFrom() {
    return from;
}

public void setFrom(Circle from) {
    this.from = from;
}

public transLine() {

    setStroke(Color.BLACK);       
    setFill(Color.ALICEBLUE);

    // doesn't work because i can't pass click event to the black line
    setMouseTransparent(true);

    // just arrow head part
    polygon = new Polygon();
    fixPolygon();


}

public void fixPolygon(){
    Point2D A = new Point2D(getEndX(),getEndY());
    Point2D Ap = new Point2D(getControlX2(),getControlY2());
    Point2D Ms = getMSecond(A,Ap,arrowHeadTransLength);

    Point2D P1 = getRotatePoint(Ms, A, Math.PI/7);
    Point2D P2 = getRotatePoint(Ms, A, -Math.PI/7);
    getPolygon().getPoints().setAll(new Double[]           
    {A.getX(),A.getY(),P1.getX(),P1.getY(),P2.getX(),P2.getY()});
}

public Point2D getMSecond(Point2D A, Point2D B, double r){
    if( A.getX()==B.getX() && A.getY()==B.getY() ){
        return B;
    }
    double a = (A.getY()-B.getY())/(A.getX()-B.getX());
    double b = A.getY()-a*A.getX();

    double xs = -r*(A.getX()-B.getX())/A.distance(B)+A.getX();
    double ys = a*xs+b;

    return new Point2D(xs,ys);
}

public Point2D getRotatePoint(Point2D P, Point2D O, double theta){
    double rx = Math.cos(theta)*(P.getX()-O.getX()) - Math.sin(theta)* 
                (P.getY()-O.getY()) + O.getX();
    double ry = Math.sin(theta)*(P.getX()-O.getX()) + Math.cos(theta)*
                (P.getY()-O.getY()) + O.getY();
    return new Point2D(rx,ry);
}

}

最佳答案

我看不出有什么特别简单的方法可以做到这一点。我认为为了使填充和曲线具有不同的鼠标行为,您需要将它们设置为不同的节点。因此,我们的想法是将曲线和填充创建为单独的部分,将它们放入 Group 中,然后在显示中使用 Group。然后使代表填充的部分对鼠标透明。

实际上实现起来有点棘手;特别是得到一条在其“内部”不响应鼠标点击的三次曲线。我能找到的唯一方法是使用由 MoveToCubicCurveTo 和另一个 CubicCurveTo 组成的 Path 沿着相反的路径返回(这确保内部基本上是空的)。然后,按照建议,将其与表示填充部分的常规 CubicCurve 放在一个组中。

SSCCE:

import javafx.application.Application;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ChangeListener;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.event.EventType;
import javafx.geometry.Point2D;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.scene.shape.Circle;
import javafx.scene.shape.CubicCurve;
import javafx.scene.shape.CubicCurveTo;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.stage.Stage;

public class ConnectingCubicCurve extends Application {

    @Override
    public void start(Stage primaryStage) {
        Circle start = createDraggingCircle(100, 100, 10, Color.CORAL);
        Circle end = createDraggingCircle(300, 300, 10, Color.CORAL);
        Connection connection = new Connection();
        connection.setFromCircle(start);
        connection.setToCircle(end);

        Pane pane = new Pane(connection.asNode(), start, end);

        pane.setOnMouseClicked(e -> System.out.println("Click on pane"));
        connection.addEventHandler(MouseEvent.MOUSE_CLICKED, e -> System.out.println("Click on connection"));
        start.setOnMouseClicked(e -> System.out.println("Click on start"));
        end.setOnMouseClicked(e -> System.out.println("Click on end"));

        Scene scene = new Scene(pane, 600, 600);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    private Circle createDraggingCircle(double centerX, double centerY, double radius, Paint fill) {
        Circle circle = new Circle(centerX, centerY, radius, fill);

        ObjectProperty<Point2D> mouseLoc = new SimpleObjectProperty<>();

        circle.setOnDragDetected(e -> 
            mouseLoc.set(new Point2D(e.getSceneX(), e.getSceneY())));
        circle.setOnMouseReleased(e -> mouseLoc.set(null));
        circle.setOnMouseDragged(e -> {
            if (mouseLoc.get() == null) return ;
            double x = e.getSceneX() ;
            double y = e.getSceneY() ;
            double deltaX = x - mouseLoc.get().getX() ;
            double deltaY = y - mouseLoc.get().getY() ;
            circle.setCenterX(circle.getCenterX() + deltaX);
            circle.setCenterY(circle.getCenterY() + deltaY);
            mouseLoc.set(new Point2D(x, y));
        });

        return circle ;
    }

    public static class Connection {

        private Path connectingLine ;
        private CubicCurve fill ;
        private Group group ;

        private ObjectProperty<Circle> fromCircle = new SimpleObjectProperty<>();
        private ObjectProperty<Circle> toCircle = new SimpleObjectProperty<>();

        public Connection() {
            connectingLine = new Path();

            MoveTo start = new MoveTo();
            CubicCurveTo curve = new CubicCurveTo();

            CubicCurveTo reverseCurve = new CubicCurveTo();
            reverseCurve.xProperty().bind(start.xProperty());
            reverseCurve.yProperty().bind(start.yProperty());
            reverseCurve.controlX1Property().bind(curve.controlX2Property());
            reverseCurve.controlX2Property().bind(curve.controlX1Property());
            reverseCurve.controlY1Property().bind(curve.controlY2Property());
            reverseCurve.controlY2Property().bind(curve.controlY1Property());

            connectingLine.getElements().addAll(start, curve, reverseCurve);

            fill = new CubicCurve();

            fill.setMouseTransparent(true);

            group = new Group();
            group.getChildren().addAll(fill, connectingLine);

            connectingLine.setStroke(Color.BLACK);
            connectingLine.setStrokeWidth(3);
            fill.setStrokeWidth(0);
            fill.setStroke(Color.TRANSPARENT);
            fill.setFill(Color.ALICEBLUE);

            fill.startXProperty().bind(start.xProperty());
            fill.startYProperty().bind(start.yProperty());
            fill.controlX1Property().bind(curve.controlX1Property());
            fill.controlX2Property().bind(curve.controlX2Property());
            fill.controlY1Property().bind(curve.controlY1Property());
            fill.controlY2Property().bind(curve.controlY2Property());
            fill.endXProperty().bind(curve.xProperty());
            fill.endYProperty().bind(curve.yProperty());

            fromCircle.addListener((obs, oldCircle, newCircle) -> {
                if (oldCircle != null) {
                    start.xProperty().unbind();
                    start.yProperty().unbind();
                }
                if (newCircle != null) {
                    start.xProperty().bind(newCircle.centerXProperty());
                    start.yProperty().bind(newCircle.centerYProperty());
                }
            });

            toCircle.addListener((obs, oldCircle, newCircle) -> {
                if (oldCircle != null) {
                    curve.xProperty().unbind();
                    curve.yProperty().unbind();
                }
                if (newCircle != null) {
                    curve.xProperty().bind(newCircle.centerXProperty());
                    curve.yProperty().bind(newCircle.centerYProperty());
                }
            });

            ChangeListener<Number> endpointListener = (obs, oldValue, newValue) -> {
                Point2D startPoint = new Point2D(start.getX(), start.getY());
                Point2D end = new Point2D(curve.getX(), curve.getY());
                Point2D vector = end.subtract(startPoint);
                Point2D perpVector = new Point2D(-vector.getY(), vector.getX());
                Point2D control1 = startPoint.add(perpVector);
                Point2D control2 = end.add(perpVector);
                curve.setControlX1(control1.getX());
                curve.setControlX2(control2.getX());
                curve.setControlY1(control1.getY());
                curve.setControlY2(control2.getY());
            };

            start.xProperty().addListener(endpointListener);
            start.yProperty().addListener(endpointListener);
            curve.xProperty().addListener(endpointListener);
            curve.yProperty().addListener(endpointListener);
        }

        public <E extends Event> void addEventHandler(EventType<E> eventType, EventHandler<E> eventHandler) {
            connectingLine.addEventHandler(eventType, eventHandler);
        }

        public <E extends Event> void removeEventHandler(EventType<E> eventType, EventHandler<E> eventHandler) {
            connectingLine.removeEventHandler(eventType, eventHandler);
        }

        public Node asNode() {
            return group ;
        }


        public final ObjectProperty<Circle> fromCircleProperty() {
            return this.fromCircle;
        }

        public final javafx.scene.shape.Circle getFromCircle() {
            return this.fromCircleProperty().get();
        }

        public final void setFromCircle(final javafx.scene.shape.Circle fromCircle) {
            this.fromCircleProperty().set(fromCircle);
        }

        public final ObjectProperty<Circle> toCircleProperty() {
            return this.toCircle;
        }

        public final javafx.scene.shape.Circle getToCircle() {
            return this.toCircleProperty().get();
        }

        public final void setToCircle(final javafx.scene.shape.Circle toCircle) {
            this.toCircleProperty().set(toCircle);
        }


    }

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

关于java - 通过形状传递鼠标单击事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32140446/

相关文章:

java - 我想在窗口 2 关闭 JAVAFX 后立即在窗口 1 上创建一个事件(添加了更多详细信息)

java - 如何使用 css 在 javafx 中为文本设置动画?

java - Spark : Merge sorted partitions

JAVAFX:有什么办法可以获得已经开放的舞台吗?

java - 部署客户端/服务器 Java 应用程序

java - 对字符串日期进行排序并对其进行排序

javafx - 如何在 FXML 中的对象元素之前创建对对象的引用?

java - 在javafx中按字母顺序选择节点

java - 在 API below 11 中移除 ActionBar

java - GWT:是否可以在添加下一个子项之前但在 CSS 规则应用于该子项之后检查父项大小?