JavaFX:获取缩放子节点相对于父节点的鼠标点击位置
解决JavaFX嵌套Pane缩放后鼠标坐标偏移问题
核心思路是利用JavaFX内置的坐标转换方法,自动处理HolderPane的缩放、平移等变换,将ListenerPane的鼠标坐标精准转换为HolderPane的本地坐标。
关键方法:坐标转换流程
JavaFX节点提供的localToScene()和sceneToLocal()方法,可自动处理所有变换(缩放、平移、旋转等),无需手动计算偏移和缩放比例:
- 获取鼠标在
ListenerPane内的本地坐标(event.getX(),event.getY()) - 将该坐标转换为场景全局坐标
- 再将场景坐标转换为
HolderPane的本地坐标,此步骤会自动应用HolderPane的所有变换
完整代码示例
1. 鼠标左键创建圆形(坐标转换核心逻辑)
listenerPane.setOnMouseClicked(event -> { if (event.getButton() == MouseButton.PRIMARY) { // 1. 获取ListenerPane内的鼠标本地坐标 double listenerX = event.getX(); double listenerY = event.getY(); // 2. 转换为场景全局坐标 Point2D scenePoint = listenerPane.localToScene(listenerX, listenerY); // 3. 转换为HolderPane的本地坐标(自动处理缩放、平移) Point2D holderLocalPoint = holderPane.sceneToLocal(scenePoint); // 创建橙色圆形,位置基于转换后的坐标 Circle circle = new Circle(holderLocalPoint.getX(), holderLocalPoint.getY(), 10, Color.ORANGE); holderPane.getChildren().add(circle); } });
2. 右键拖动平移HolderPane
// 记录拖动初始状态的变量 private double initialMouseX, initialMouseY; private double initialTranslateX, initialTranslateY; listenerPane.setOnMousePressed(event -> { if (event.getButton() == MouseButton.SECONDARY && !event.isAltDown()) { initialMouseX = event.getSceneX(); initialMouseY = event.getSceneY(); initialTranslateX = holderPane.getTranslateX(); initialTranslateY = holderPane.getTranslateY(); } }); listenerPane.setOnMouseDragged(event -> { if (event.getButton() == MouseButton.SECONDARY && !event.isAltDown()) { double deltaX = event.getSceneX() - initialMouseX; double deltaY = event.getSceneY() - initialMouseY; holderPane.setTranslateX(initialTranslateX + deltaX); holderPane.setTranslateY(initialTranslateY + deltaY); } });
3. 滚轮缩放HolderPane(以鼠标位置为中心)
listenerPane.setOnScroll(event -> { double scaleFactor = event.getDeltaY() > 0 ? 1.1 : 0.9; // 获取鼠标在HolderPane内的坐标,作为缩放中心 Point2D scenePoint = listenerPane.localToScene(event.getX(), event.getY()); Point2D holderLocalCenter = holderPane.sceneToLocal(scenePoint); // 调整平移量,保证缩放中心固定 holderPane.setTranslateX(holderPane.getTranslateX() + holderLocalCenter.getX() * (1 - scaleFactor)); holderPane.setTranslateY(holderPane.getTranslateY() + holderLocalCenter.getY() * (1 - scaleFactor)); // 执行缩放 holderPane.setScaleX(holderPane.getScaleX() * scaleFactor); holderPane.setScaleY(holderPane.getScaleY() * scaleFactor); });
4. Alt+右键重置位置和缩放
listenerPane.setOnMouseClicked(event -> { if (event.getButton() == MouseButton.SECONDARY && event.isAltDown()) { holderPane.setTranslateX(0); holderPane.setTranslateY(0); holderPane.setScaleX(1); holderPane.setScaleY(1); } });
为什么之前的方法失效?
手动计算event.getX() - HolderPane.getTranslateX()仅考虑了平移,完全忽略了缩放的影响——缩放后HolderPane的单位坐标长度与ListenerPane不一致,直接相减会导致位置偏移。而sceneToLocal()会自动解析HolderPane的scaleX/Y、translateX/Y等变换参数,输出精准的本地坐标。
内容的提问来源于stack exchange,提问作者Runsva
相关产品推荐
相关产品推荐

