如何在 JavaFX 8 中通过事件位置拖动鼠标时获取节点?

How to get Node while mouse dragged by event position in JavaFX 8?

我已经创建了代码示例:

package Whosebug;

import javafx.application.Application;
import javafx.geometry.Point2D;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Line;
import javafx.stage.Stage;

public class GetNodeByMousePositionWhileDragged extends Application {

    private Line line;
    private Group group = new Group();

    @Override
    public void start(Stage stage) throws Exception {

        AnchorPane anchorPane = new AnchorPane();

        Circle source = new Circle(30, Color.LIGHTGREEN);
        source.setStroke(Color.BLACK);
        source.setCenterX(100);
        source.setCenterY(100);

        source.setOnMousePressed(me -> {

            me.consume();

            drawLine(source, me);
        });

        source.setOnMouseDragged(me -> translateLineEnd(getPoint(me)));

        source.setOnMouseReleased(event -> group.getChildren().remove(line));

        Circle target = new Circle(30, Color.LIGHTBLUE);
        target.setStroke(Color.BLACK);
        target.setCenterX(400);
        target.setCenterY(100);

        target.setOnMousePressed(me -> {

            me.consume();

            drawLine(target, me);
        });

        target.setOnMouseDragged(me -> translateLineEnd(getPoint(me)));

        target.setOnMouseReleased(event -> group.getChildren().remove(line));

        group.getChildren().addAll(source, target);

        anchorPane.getChildren().addAll(group);

        stage.setScene(new Scene(anchorPane, 600, 400));
        stage.setMaximized(true);
        stage.show();

    }

    private void drawLine(Circle source, MouseEvent me) {

        line = new Line();
        line.setStroke(Color.BLACK);
        line.setStrokeWidth(1);

        line.startXProperty().bind(source.centerXProperty());
        line.startYProperty().bind(source.centerYProperty());

        translateLineEnd(getPoint(me));

        group.getChildren().add(line);
    }

    private void translateLineEnd(Point2D point) {

        line.setEndX(point.getX());
        line.setEndY(point.getY());
    }

    private Point2D getPoint(MouseEvent me) {

        return new Point2D(me.getSceneX(), me.getSceneY());
    }
}

这里我只是添加了两个圆圈,我想通过简单地从一个圆圈拖动到另一个圆圈来将它们连接成一条线。但问题是我想在从源圈拖动鼠标时验证鼠标是否进入目标圈。输入时,我只想将线的端点绑定到目标圆的中心点,或者如果没有输入除源一以外的任何圆,则释放鼠标上的线。

不幸的是,当拖动一个圆圈时,另一个圆圈没有捕捉到鼠标事件。但是可以获得鼠标在场景中的位置。我试图通过简单地存储所有圆圈(我有一堆,10K+),每次迭代并检查 circle.contains(me.getSceneX(), me.getSceneY()) 来解决这个问题。在我看来这有点昂贵或像发明轮子。

有一个问题,在 JavaFX 8 中是否可以通过使用内置的 JavaFX 功能以正确的方式根据场景位置获取节点?

您需要稍微修改一下代码:

  • 通过为 onDragDetected 事件中的源节点调用 startFullDrag 使用 MouseDragEvents。
  • 将行的 mouseTransparent 设置为 true 以允许 JavaFX 将 MouseEvent 传送到 target 圈而不是 Line
  • 如果鼠标在目标圆圈上松开,修改事件处理程序以产生不同的结果。
private void drawLine(Circle source, MouseEvent me) {

    line = new Line();
    line.setMouseTransparent(true);
    ...
private Group group = new Group();

private boolean removeLine = true;
source.setOnMousePressed(me -> {
    me.consume();

    drawLine(source, me);
    me.setDragDetect(true); // trigger dragDetected event immediately
});
source.setOnDragDetected(evt -> {
    source.startFullDrag();
    removeLine = true;
});

...

source.setOnMouseReleased(event -> {
    if (removeLine) {
        group.getChildren().remove(line);
    }
});
target.setOnMouseDragReleased(me -> removeLine = false);