JavaFX:任务栏位置变更时如何更新最大化无装饰窗口的宽高?
问题描述
我希望让处于最大化状态的Undecorated(无装饰)窗口,在任务栏位置发生变更时自动调整大小。
我曾尝试通过onMouseMove事件,借助getVisualBounds()检测屏幕尺寸变化来实现,但该方案存在问题:只有当鼠标移过窗口时才会触发窗口调整,无法在任务栏位置变更后立即生效。
以下是我编写的演示代码:
/////// controller Class//////// private Stage stage; boolean lock = false; ObservableList<Screen> screenSizes; public void setUp(Stage stage){ this.stage = stage; screenSizes = Screen.getScreensForRectangle(new Rectangle2D(this.stage.getX(), this.stage.getY(), this.stage.getWidth(), this.stage.getHeight())); } @FXML protected void onMaximizedButton() { if(lock == true){ stage.setMaximized(false); lock = false; }else{ stage.setMaximized(true); lock = true; stage.setX(screenSizes.get(0).getVisualBounds().getMinX()); stage.setY(screenSizes.get(0).getVisualBounds().getMinY()); stage.setWidth(screenSizes.get(0).getVisualBounds().getWidth()); stage.setHeight(screenSizes.get(0).getVisualBounds().getHeight()); } } @FXML private void onMouseMove(){ ObservableList<Screen> newScreenSizes = Screen.getScreensForRectangle(new Rectangle2D(stage.getX(), stage.getY(), stage.getWidth(),stage.getHeight())); if(!(newScreenSizes.get(0).getVisualBounds().equals(screenSizes.get(0).getVisualBounds()))) if(lock == true){ //stage.setMaximized(true); screenSizes = newScreenSizes; stage.setX(screenSizes.get(0).getVisualBounds().getMinX()); stage.setY(screenSizes.get(0).getVisualBounds().getMinY()); stage.setWidth(screenSizes.get(0).getVisualBounds().getWidth()); stage.setHeight(screenSizes.get(0).getVisualBounds().getHeight()); } } ///// main class//////// @Override public void start(Stage stage) throws IOException { FXMLLoader fxmlLoader = new FXMLLoader(HelloApplication.class.getResource("hello-view.fxml")); Parent root = fxmlLoader.load(); HelloController helloController = fxmlLoader.getController(); Scene scene = new Scene(root, 320, 240); stage.setTitle("Hello!"); stage.setScene(scene); stage.initStyle(StageStyle.UNDECORATED); stage.show(); helloController.setUp(stage); } public static void main(String[] args) { launch(); }
我想询问是否有方法可以获取任务栏位置,并在其变更时更新窗口大小?
我还考虑过一种未实践的思路:为Screen的ObservableList添加监听器,将其与窗口绑定以实现任务栏变更时的自动调整。
解决方案
你提到的为Screen的ObservableList添加监听器的思路完全可行,这能在屏幕可视区域(包含任务栏变化)发生改变时立即触发窗口调整,无需依赖鼠标事件。
具体实现步骤
- 在
setUp方法中,为Screen.getScreens()的ObservableList添加监听器,处理屏幕新增/移除的场景;同时监听当前屏幕的visualBoundsProperty,捕捉任务栏位置/大小变更。 - 封装统一的窗口边界更新方法,在触发条件满足时调用。
修改后的控制器代码示例:
/////// controller Class//////// private Stage stage; boolean lock = false; Screen currentScreen; public void setUp(Stage stage){ this.stage = stage; // 初始化当前屏幕 currentScreen = Screen.getScreensForRectangle(stage.getX(), stage.getY(), stage.getWidth(), stage.getHeight()).get(0); // 监听屏幕列表变化(多屏幕切换/新增/移除) Screen.getScreens().addListener((ListChangeListener<Screen>) change -> { while (change.next()) { if (lock) { updateMaximizedWindowBounds(); } } }); // 监听当前屏幕可视区域变化(任务栏位置/大小变更会触发) currentScreen.visualBoundsProperty().addListener((obs, oldBounds, newBounds) -> { if (lock) { updateMaximizedWindowBounds(); } }); } // 统一更新窗口边界的方法 private void updateMaximizedWindowBounds() { currentScreen = Screen.getScreensForRectangle(stage.getX(), stage.getY(), stage.getWidth(), stage.getHeight()).get(0); Bounds visualBounds = currentScreen.getVisualBounds(); stage.setX(visualBounds.getMinX()); stage.setY(visualBounds.getMinY()); stage.setWidth(visualBounds.getWidth()); stage.setHeight(visualBounds.getHeight()); } @FXML protected void onMaximizedButton() { if(lock == true){ stage.setMaximized(false); lock = false; }else{ lock = true; updateMaximizedWindowBounds(); // 无装饰窗口的setMaximized(true)可能无法自动适配任务栏,因此手动设置边界更可靠 // stage.setMaximized(true); } } // 可移除onMouseMove方法,监听器已能自动触发调整
补充说明
Screen.visualBoundsProperty()是核心:它会在屏幕可用区域(排除任务栏、dock等系统UI)发生变化时立即回调,完美覆盖任务栏位置变更的场景。- 间接获取任务栏位置:JavaFX没有直接获取任务栏位置的API,但可以通过屏幕物理尺寸和可视区域的差值判断:
Bounds fullScreen = currentScreen.getBounds(); Bounds usableArea = currentScreen.getVisualBounds(); // 任务栏在底部:fullScreen.getHeight() - usableArea.getHeight() 即为任务栏高度 // 任务栏在右侧:fullScreen.getWidth() - usableArea.getWidth() 即为任务栏宽度
内容的提问来源于stack exchange,提问作者TookLong
相关产品推荐
相关产品推荐

