MouseEntered/Exited 悬停在相邻节点上时未触发

MouseEntered/Exited not fired when hovering over adjacent nodes

我有两个 javafx.scene.shape.Box 个彼此相邻的实例:

我希望在所选节点发生变化时收到通知,即每当鼠标进入或离开红色或蓝色节点时。

将鼠标从黑色移动到任何彩色框会正确触发 "mouse entered" 事件(反之亦然,从 red/blue 移动到黑色会触发 "mouse exited" 事件)。

但是,将鼠标从红色直接移动到蓝色(或从蓝色直接移动到红色)不会触发任何事件。

import javafx.application.Application;
import javafx.scene.*;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.Box;
import javafx.stage.Stage;

public class Demo extends Application {

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

    @Override
    public void start(Stage stage) {
        Box redBox = new Box(100, 100, 100);
        redBox.setId("red");
        redBox.setMaterial(new PhongMaterial(Color.RED));
        redBox.setTranslateX(100);
        redBox.setTranslateY(100);
        redBox.setTranslateZ(20);

        Box blueBox = new Box(100, 100, 100);
        blueBox.setId("blue");
        blueBox.setMaterial(new PhongMaterial(Color.BLUE));
        blueBox.setTranslateX(200);
        blueBox.setTranslateY(100);
        blueBox.setTranslateZ(20);

        PointLight pointLight = new PointLight(Color.ANTIQUEWHITE);
        pointLight.setTranslateX(800);
        pointLight.setTranslateY(-100);
        pointLight.setTranslateZ(-1000);

        Group root = new Group(redBox, blueBox);
        root.getChildren().add(pointLight);

        root.setOnMouseEntered(me -> {
            System.out.println("Entered " + resolvePickedId(me));
        });

        root.setOnMouseExited(me -> {
            System.out.println("Exited " + resolvePickedId(me));
        });

        Scene scene = new Scene(root, 300, 200, true);
        scene.setFill(Color.rgb(10, 10, 40));
        scene.setCamera(new PerspectiveCamera(false));
        stage.setScene(scene);
        stage.show();
    }

    private static String resolvePickedId(MouseEvent me) {
        Node intersectedNode = me.getPickResult().getIntersectedNode();
        return intersectedNode == null ? "(none)" : intersectedNode.getId();
    }

}

我错过了什么?

您必须将 MouseListener 添加到 blueBoxredBox 而不是 root。当您将 MouseListener 添加到 root 时,您只会在 leaving/entering root 时收到通知,因此在更改 root 元素内的元素时不会发生任何事件。

您设置了这两个框的 Group root,每当您 enterexit 这个组时,您的事件就会被触发。这就是正在发生的事情。由于两个框都是组的子项,您不会收到通知,因为您的听众正在寻找组,而不是它的子项。

要么你直接创建一个 MouseListener 到盒子,要么你可以做一些事情,比如跟踪当前节点,并检查 OnMouseMoved 是否有变化:

//in the class, new variable
Node save = null;

//.... in the start method

root.setOnMouseEntered(me -> {
    System.out.println("Entered " + resolvePickedId(me));
    save = me.getPickResult().getIntersectedNode();
});

root.setOnMouseMoved(me ->{
    if(me.getPickResult().getIntersectedNode() != save){
        System.out.println("Changed to "+resolvePickedId(me));
        save = me.getPickResult().getIntersectedNode();
    }
});

root.setOnMouseExited(me -> {
    System.out.println("Exited " + resolvePickedId(me));
    save = null;
});