问题是isHover 真的会返回false,因为MOUSE_ENTERED 事件不会触发到您的Nodes(它仅在您开始拖动的Node 上触发)。
来自isHover()的文档:
请注意,当前的悬停实现依赖于鼠标输入和
退出事件判断该Node是否处于悬停状态;
为了了解发生了什么,我在这里复制了MouseEvent documentation 的一部分(重点是我的):
拖动手势分为三种。它们都是由
鼠标按下事件并因鼠标释放而终止
事件,源节点决定将发生哪个手势。
默认是简单的按下-拖动-释放手势。最好习惯
允许改变形状的大小,拖动它等等。 整体
按下-拖动-释放手势传递到一个节点。 当鼠标按钮
被按下,最上面的节点被拾取,所有后续的鼠标
事件被传递到同一个节点,直到按钮被释放。如果
从这些事件中生成鼠标单击事件,它仍然是
投递到同一个节点。
在简单的按下-拖动-释放手势期间,其他节点不
参与并且没有得到任何事件。如果这些节点需要参与
在手势中,必须激活完整的按下-拖动-释放手势。
此手势最适合通过“电线”连接节点,拖动
节点到其他节点等。更详细地描述了这种手势类型
在 MouseDragEvent 中,它包含传递给手势的事件
目标。
所以,我第一句话中的“拖动”是文档中的第一种拖动,它不能与其他 Nodes 一起使用,因此不会为 Nodes 触发鼠标输入事件用于isHover方法中的计算。
在您的情况下,您需要第二种类型的拖动,因此您必须在节点之间实现拖动机制。一个非常好的起点是official tutorial。
这是一个使用Circles 实现 DnD 的 SSCCE(没有画线)
public class Main extends Application {
@Override
public void start(Stage primaryStage) {
try {
BorderPane root = new BorderPane();
Scene scene = new Scene(root, 400, 400);
List<NFANode> nfaNodes = new LinkedList<>();
Pane pane = new Pane();
root.setCenter(pane);
// On pane click we add circles
pane.setOnMouseClicked(event -> {
if (event.getButton().equals(MouseButton.PRIMARY)) {
// If any of the nodes are in hover, do not add new circle
if (nfaNodes.stream().anyMatch(n -> n.getCircle().isHover()))
return;
// Create and initialize the circle, add it to the pane
// Wrap it in a NFANode and add it to the list
Circle circle = new Circle();
NFANode nfaNode = new NFANode(circle);
nfaNodes.add(nfaNode);
pane.getChildren().add(circle);
circle.setCenterX(event.getX());
circle.setCenterY(event.getY());
circle.setRadius(20);
// Circle started to be dragged
circle.setOnDragDetected(ev -> {
System.out
.println("Drag detected on circle: " + circle.getBoundsInParent());
// The content will be linked
Dragboard db = circle.startDragAndDrop(TransferMode.LINK);
// Add the index of the NFANode to the DragBoard
ClipboardContent content = new ClipboardContent();
content.putString(new Integer(nfaNodes.indexOf(nfaNode)).toString());
db.setContent(content);
});
// A circle is hovered while in a drag
circle.setOnDragOver(e -> {
// Only accept different nodes than the source
if (e.getGestureSource() != circle) {
String content = e.getDragboard().getContent(DataFormat.PLAIN_TEXT).toString();
Circle draggedCircle = nfaNodes.get(Integer.parseInt(content)).getCircle();
System.out.println("Drag over circle: " + circle.getBoundsInParent());
System.out.println("Circle dragged: " + draggedCircle.getBoundsInParent());
e.acceptTransferModes(TransferMode.ANY);
}
event.consume();
});
// Drag finished on a node
circle.setOnDragDropped(e -> {
String content = e.getDragboard().getContent(DataFormat.PLAIN_TEXT).toString();
Circle draggedCircle = nfaNodes.get(Integer.parseInt(content)).getCircle();
System.out.println("Drag completed over circle: " + circle.getBoundsInParent());
System.out.println("Circle dragged: " + draggedCircle.getBoundsInParent());
e.acceptTransferModes(TransferMode.ANY);
});
}
});
primaryStage.setScene(scene);
primaryStage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
public class NFANode {
private Circle circle;
public NFANode(Circle circle) {
this.circle = circle;
}
public Circle getCircle() {
return circle;
}
public void setCircle(Circle circle) {
this.circle = circle;
}
}
public static void main(String[] args) {
launch(args);
}
}
以及示例输出:
Drag detected on circle: BoundingBox [minX:73.0, minY:97.0, minZ:0.0, width:40.0, height:40.0, depth:0.0, maxX:113.0, maxY:137.0, maxZ:0.0]
Drag over circle: BoundingBox [minX:275.0, minY:289.0, minZ:0.0, width:40.0, height:40.0, depth:0.0, maxX:315.0, maxY:329.0, maxZ:0.0]
Circle dragged: BoundingBox [minX:73.0, minY:97.0, minZ:0.0, width:40.0, height:40.0, depth:0.0, maxX:113.0, maxY:137.0, maxZ:0.0]
Drag completed over circle: BoundingBox [minX:275.0, minY:289.0, minZ:0.0, width:40.0, height:40.0, depth:0.0, maxX:315.0, maxY:329.0, maxZ:0.0]
Circle dragged: BoundingBox [minX:73.0, minY:97.0, minZ:0.0, width:40.0, height:40.0, depth:0.0, maxX:113.0, maxY:137.0, maxZ:0.0]