获取节点上鼠标相对于其坐标和变换的位置

5

我有一个3D场景,场景内有一个带有沿x轴旋转变换的面板,我想将此面板用作策略游戏棋盘,但遇到了问题。

当我将鼠标移动到面板内时,它会给出错误的光标位置。

例如,当我从面板的左上角(红色圆圈)进入面板(带有黑色边框的旋转面板)时,应在面板内显示(0,0)的光标位置,但实际上它显示的是类似于(200,400)的数字。

rotated pane with black border

如何解决这个问题?

或者说,如何相对于节点和其转换得到节点上的鼠标坐标?

以下是一个示例:

import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import javafx.scene.transform.RotateBuilder;
import javafx.stage.Stage;


public class JFXRotationXOrds  extends Application{

    @Override
    public void start(Stage primaryStage) throws Exception {
        VBox root = new VBox();
        root.getChildren().add(new Rectangle(20, 20, Color.BLUE));  
        root.getChildren().add(new Circle(20, Color.RED));
        //root.rotateProperty().set(30);
        root.getTransforms().add(RotateBuilder.create().angle(-30).pivotX(0).pivotY(100).axis(new Point3D(1, 0, 0)).build());
        root.setStyle("-fx-border-color: black; -fx-border-width:5; ");

        root.setOnMouseMoved(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent arg0) {
                if(arg0.getEventType() == MouseEvent.MOUSE_MOVED){
                    System.out.println(arg0.getX() + "," + arg0.getY());
                }

            }
        });

        Scene scene = new Scene(root, 200, 500);
        primaryStage.setTitle("Rotation Coordinates Example");
        primaryStage.setScene(scene);
        scene.setCamera(PerspectiveCameraBuilder.create().fieldOfView(10).build());
        primaryStage.show();

    }

    public static void main(String[] args){
        Application.launch(args);
    }
}
2个回答

3

更新

问题已经在JDK8早期访问版本中得到解决。您可以下载该版本,或等待它发布。该问题已在二月份作为此票的一部分得到解决:RT-28129

编辑

我在JavaFX Jira上提交了一个问题单。您可以关注它以查看状态更新。

我已经更新了演示以反映您的问题。当变换使用z轴(昨天)时似乎有效,但当变换在X或Y轴上时则无效。

希望这能对您有所帮助。

import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.geometry.Point3D;
import javafx.scene.PerspectiveCamera;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.VBox;
import javafx.scene.transform.Rotate;
import javafx.scene.transform.RotateBuilder;
import javafx.stage.Stage;


public class JFXRotationXOrds  extends Application{

    @Override
    public void start(Stage primaryStage) throws Exception {
        VBox root = new VBox();
        final Rotate rotate = RotateBuilder.create().angle(80).pivotX(100).pivotY(100).pivotZ(0).axis(new Point3D(1,0,0)).build();
        root.getTransforms().add(rotate);
        root.setStyle("-fx-border-color: black; -fx-border-width:5; ");

        root.setOnMouseMoved(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent arg0) {
                if(arg0.getEventType() == MouseEvent.MOUSE_MOVED){
                    System.out.println(arg0.getSceneX() + "," + arg0.getSceneY());
                }
            }
        });

        Scene scene = new Scene(root, 200, 500);
        PerspectiveCamera camera = new PerspectiveCamera();
        scene.setCamera(camera);
        primaryStage.setTitle("BorderPane Example");
        primaryStage.setScene(scene);
        primaryStage.show();

    }

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

在二维中它运行良好,但在三维中不行,请尝试为您的根添加3D旋转并为场景设置透视相机。 - Eeliya
啊 - 你确实说了绕X轴旋转,但是你的截图似乎表明是绕Z轴旋转。现在我能看出问题所在了...我想你可以使用这里的公式进行一些计算(但还没有做数学证明):http://docs.oracle.com/javafx/2/api/javafx/scene/transform/Affine.html - Nick Rippe
1
@Eeliya - 问题似乎已经在JDK8早期访问版本中得到解决。有关更多详细信息,请参见答案更新。 - Nick Rippe

0

由于您没有发布任何代码,这可能很明显,但是您是否将鼠标事件处理程序添加到了窗格中?如果是的话(在我尝试重新创建您的问题时),event.getX()和event.getY()方法返回了预期的位置。

(您是否使用了getSceneX()和getSceneY()?在这种情况下,请更改为getX()和getY())

另一种方法是通过您的窗格位置来纠正您获得的鼠标位置(场景上的位置)。

您可以对x、y、z轴执行此操作:

while (node != null){
   shift += node.getLayoutY(); 
   node = node.getParent();
}

然后从指针的位置减去这个偏移量。

编辑:查看您的代码后,似乎您将MouseEvent处理程序添加到了根对象中。因此,当鼠标在根对象上时触发事件。例如,如果您将其添加到矩形中,则鼠标的位置将相对于矩形。

以下代码对我有效(但可能无法很好地重现您的问题)。

public class JFXRotationXOrds extends Application {

@Override
public void start(Stage primaryStage) throws Exception {
    VBox root = new VBox();

    Rectangle rect = new Rectangle(20, 20, Color.BLUE);
    rect.setOnMouseMoved(new EventHandler<MouseEvent>() {
        @Override
        public void handle(MouseEvent arg0) {
            if(arg0.getEventType() == MouseEvent.MOUSE_MOVED){
                System.out.println("Rect : " + arg0.getX() + "," + arg0.getY());
            }

        }
    });
    root.getChildren().add(rect);  
    root.getChildren().add(new Circle(20, Color.RED));
    //root.rotateProperty().set(30);
    root.getTransforms().add(RotateBuilder.create().angle(30).pivotX(0).pivotY(100).pivotZ(100).build());
    root.setStyle("-fx-border-color: black; -fx-border-width:5; ");

    root.setOnMouseMoved(new EventHandler<MouseEvent>() {
        @Override
        public void handle(MouseEvent arg0) {
            if(arg0.getEventType() == MouseEvent.MOUSE_MOVED){
                System.out.println(arg0.getX() + "," + arg0.getY());
            }

        }
    });

    Scene scene = new Scene(root, 200, 500);
    primaryStage.setTitle("Rotation Coordinates Example");
    primaryStage.setScene(scene);
    primaryStage.show();

}

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

我测试了您的编辑,结果没有变化。仍然报告基于未转换节点的x/y坐标。 :/ - Nick Rippe
所以您将鼠标移动事件添加到矩形中,然后将该矩形添加到根节点中?我会深入了解一下。 - Marc
@NickRippe 编辑后的代码对我来说似乎可行... 在你的演示中,你将事件添加到了根节点。 - Marc
您没有设置旋转轴。只有当旋转轴不是Z轴时才会出现问题(默认情况下为Z轴)。您编辑的示例未设置轴,因此它在Z轴上旋转。尝试将以下内容添加到您的构建器中:.axis(new Point3D(1, 0, 0)) - Nick Rippe
我已经设置了轴。我需要获取具有3D变换的节点上的鼠标坐标。在2D中,我可以做到这一点。但我需要3D。 - Eeliya
不是指你,@Eeliya - 我是在指Marc的例子。它很好用,直到你加入3D元素。 - Nick Rippe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接