【问题标题】:JavaFX: Node#isHover doesn't recognize if I'm hovering over itJavaFX:Node#isHover 无法识别我是否将鼠标悬停在它上面
【发布时间】:2016-11-14 06:37:49
【问题描述】:

我正在尝试创建一个属性,当我将一条线从一个节点拖到另一个节点时识别该属性。

但是,当它被悬停时,另一个节点似乎无法识别。

为了得到一个想法,这里是这个过程的图像:

下面是我用来让它在拖动鼠标时执行操作的代码:

nfaNode.setOnMouseDragged(event1 -> {
    nfaNode.setDelete(false);
    final Point2D mouseInParent = nfaNode.localToParent(event1.getX(), event1.getY());
    if (event1.isShiftDown()) {
        nfaNode.getArrow().setVisible(true);
        nfaNode.setArrowBounds(nfaNode.getBubble().getCenterX(), nfaNode.getBubble().getCenterY(),
                event1.getX(), event1.getY());
        nfaNodes.stream().filter(n -> n.isHover() && !n.equals(nfaNode)).forEach(n -> System.out.println("Hovering over " + n.getText().getText()));
        return;
    }
    nfaNode.getArrow().setVisible(false);
    nfaNode.setLayoutX(mouseInParent.getX() + dragDelta.getDragDeltaX());
    nfaNode.setLayoutY(mouseInParent.getY() + dragDelta.getDragDeltaY());
});

当我从 Q_0 拖动到 Q_1 时,Q_1 无法识别我的鼠标,是否有原因?

【问题讨论】:

    标签: java javafx drag-and-drop


    【解决方案1】:

    问题是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]
    

    【讨论】:

    • 谢谢,通过这个,好像能识别手势了。但是,db#setContent(content) 似乎不允许我将节点拖过几个像素。
    【解决方案2】:

    聚会有点晚了,但这对我有帮助: https://examples.javacodegeeks.com/desktop-java/javafx/event-javafx/javafx-drag-drop-example/

    FxDragDropExample1 解释了一切。我不确定你是否也实现了这个事件处理程序:

    sourceFld.setOnDragDetected(new EventHandler <MouseEvent>()
    {
      public void handle(MouseEvent event)
      {
        sourceFld.startFullDrag();
        writelog("Event on Source: drag detected");
      }
    });
    

    阅读https://docs.oracle.com/javase/8/javafx/api/javafx/scene/input/MouseDragEvent.html了解更多信息。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-04-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-29
      • 1970-01-01
      相关资源
      最近更新 更多