You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaFX:获取缩放子节点相对于父节点的鼠标点击位置

解决JavaFX嵌套Pane缩放后鼠标坐标偏移问题

核心思路是利用JavaFX内置的坐标转换方法,自动处理HolderPane的缩放、平移等变换,将ListenerPane的鼠标坐标精准转换为HolderPane的本地坐标。

关键方法:坐标转换流程

JavaFX节点提供的localToScene()和sceneToLocal()方法,可自动处理所有变换(缩放、平移、旋转等),无需手动计算偏移和缩放比例:

  1. 获取鼠标在ListenerPane内的本地坐标(event.getX(), event.getY())
  2. 将该坐标转换为场景全局坐标
  3. 再将场景坐标转换为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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 17:45:55