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

JavaFX问题:多次显示Stage时组件无法跟随光标位置更新

JavaFX AnchorPane 光标位置跟随问题解决方案

问题回顾

我编写的JavaFX程序中,一个AnchorPane在首次启动时能正常显示在光标位置(通过initialize()调用setUiPosition()实现),但隐藏或关闭primaryStage后再次实例化显示时,组件位置固定在首次显示的位置,不再跟随光标。

环境:JDK 21、JavaFX 21.0.1、JNativeHook 2.2.2,使用SceneBuilder开发。

核心原因

  1. initialize()仅执行一次:FXML控制器的initialize()方法仅在FXML首次加载时触发,后续重新显示Stage不会再次执行,导致位置更新逻辑只运行了一次。
  2. Stage/布局缓存复用:关闭Stage后若未正确销毁实例,再次显示时可能复用了之前的位置缓存,未重新计算光标坐标。
  3. 光标位置获取未实时更新:若setUiPosition()依赖JNativeHook的监听缓存,而非实时获取光标位置,会导致位置数据过期。

可行解决方案

1. 在Stage显示前强制更新位置

放弃仅在initialize()中更新位置的逻辑,改为每次显示Stage前主动调用位置更新方法:

// 针对已存在的Stage,添加显示事件监听
Stage stage = (Stage) anchorPane.getScene().getWindow();
stage.setOnShown(event -> setUiPosition());

// 若每次重新创建Stage,在show()前调用更新
FXMLLoader loader = new FXMLLoader(getClass().getResource("your-view.fxml"));
AnchorPane pane = loader.load();
Stage newStage = new Stage(new Scene(pane));

// 获取控制器并更新位置
YourController controller = loader.getController();
controller.setUiPosition();

newStage.show();

2. 监听AnchorPane可见性变化

给AnchorPane添加可见性监听器,当组件变为可见时自动更新位置:

anchorPane.visibleProperty().addListener((observable, oldVisible, newVisible) -> {
    if (newVisible) {
        setUiPosition();
    }
});

3. 实时获取光标位置

优化setUiPosition()方法,直接实时获取光标坐标,避免依赖缓存数据:

// 工具类中实现实时获取光标位置
public class Utils {
    public static Point getCurrentCursorPos() {
        return MouseInfo.getPointerInfo().getLocation();
    }
}

// 控制器中的位置更新方法
private void setUiPosition() {
    Point cursor = Utils.getCurrentCursorPos();
    Stage stage = (Stage) anchorPane.getScene().getWindow();
    // 可根据需求调整偏移量,比如让组件中心对齐光标
    stage.setX(cursor.getX() - anchorPane.getWidth() / 2);
    stage.setY(cursor.getY() - anchorPane.getHeight() / 2);
}

4. 正确管理Stage生命周期

避免复用已关闭的Stage实例,每次需要显示时创建新的Stage:

public void showAnchorPane() {
    try {
        FXMLLoader loader = new FXMLLoader(getClass().getResource("your-view.fxml"));
        AnchorPane root = loader.load();
        Stage newStage = new Stage(new Scene(root));
        
        loader.getController().setUiPosition();
        newStage.show();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

内容的提问来源于stack exchange,提问作者Crystian Sorato

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 15:52:53