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

Java窗口程序切换全屏模式时调用setUndecorated(true)抛出IllegalComponentStateException的解决方案咨询

Java窗口程序切换全屏模式时调用setUndecorated(true)抛出IllegalComponentStateException的解决方案咨询

看起来你在给Java Swing程序加全屏切换功能时遇到了经典的Swing限制问题——窗口显示后就没法直接修改undecorated状态了,我来帮你梳理下可行的解决思路和调整方案。

先搞懂报错原因

Swing的底层规则是:一旦窗口已经显示(isDisplayable()返回true),就不能再调用setUndecorated(),因为这个操作会改变窗口的底层原生组件结构,而窗口显示时原生资源已经被创建绑定了,所以才会抛出IllegalComponentStateException。你在初始化时能成功,就是因为当时窗口还没调用setVisible(true),还处于不可显示状态。

解决方案1:修改切换逻辑,先隐藏窗口再调整

你可以修改toggleFullScreen()方法,在调整undecorated状态前先把窗口隐藏,调整完成后再显示回来,具体代码调整如下:

void toggleFullScreen() {
    boolean shouldDisplayFullScreen = GameController.isOptionEnabled(GameController.Options.FULL_SCREEN);
    GraphicsDevice gd = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();

    // 先隐藏窗口,避免修改undecorated时报错
    setVisible(false);

    if (shouldDisplayFullScreen) {
        Core.saveProgramProps(); // Store current window size and position
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        setExtendedState(JFrame.NORMAL); // Reset state before changing size
        setUndecorated(true);           
        setJMenuBar(null); // Hide the menu bar            
        setSize(screenSize.width, screenSize.height);
        setLocation(0, 0);
        setAlwaysOnTop(true);
        setResizable(false);
    } else {
        // Restore windowed mode
        setAlwaysOnTop(false);
        applyPropsWindowSize();
        applyPropsWindowPosition();
        toggleMenuBarVisibility(); // Restore the menu bar depending on props
        setResizable(true);
        setUndecorated(false);
    }

    validate();
    // 重新显示窗口
    setVisible(true);
}

这个方法简单直接,切换过程中可能会有短暂的窗口闪烁,但大部分场景下用户可以接受。

解决方案2:使用Swing的全屏独占模式(更推荐)

你之前尝试过GraphicsDevice.setFullScreenWindow(),其实这才是Swing官方推荐的全屏实现方式,它会自动处理窗口装饰、全屏适配,还能避免窗口被其他窗口遮挡的问题。我们可以把切换逻辑改成基于这个API的:

// 需要在类里添加成员变量保存窗口状态
private int savedWindowState;
private Rectangle savedBounds;

void toggleFullScreen() {
    boolean shouldDisplayFullScreen = GameController.isOptionEnabled(GameController.Options.FULL_SCREEN);
    GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
    GraphicsDevice gd = env.getDefaultScreenDevice();

    if (shouldDisplayFullScreen) {
        if (gd.isFullScreenSupported()) {
            Core.saveProgramProps();
            // 保存当前窗口状态,用于恢复
            savedWindowState = getExtendedState();
            savedBounds = getBounds();
            
            // 切换到全屏独占模式
            setJMenuBar(null);
            gd.setFullScreenWindow(this);
            setResizable(false);
        } else {
            // 如果不支持全屏独占,退而求其次用窗口最大化+无装饰
            setVisible(false);
            setUndecorated(true);
            setExtendedState(JFrame.MAXIMIZED_BOTH);
            setJMenuBar(null);
            setAlwaysOnTop(true);
            setVisible(true);
        }
    } else {
        // 恢复窗口模式
        gd.setFullScreenWindow(null);
        setVisible(false);
        setUndecorated(false);
        setResizable(true);
        setAlwaysOnTop(false);
        // 恢复之前保存的窗口状态和位置
        setExtendedState(savedWindowState);
        setBounds(savedBounds);
        toggleMenuBarVisibility();
        setVisible(true);
    }
}

这种方式的优势是:

  • 真正的全屏,不会被其他窗口遮挡
  • 自动适配屏幕分辨率,不需要手动设置大小位置
  • 符合Swing的最佳实践,减少底层资源冲突

额外解决你遇到的小问题

  • 切换后窗口消失在其他窗口后面:用全屏独占模式的话这个问题会自动解决;如果用方案1,确保setAlwaysOnTop(true)是在窗口显示前设置好的。
  • 退出选项菜单时总是触发恢复逻辑:你可以在选项菜单里添加一个标记,记录全屏选项是否真的被修改,只有当选项状态变化时才执行切换逻辑,而不是每次关闭菜单都执行。

备注:内容来源于stack exchange,提问作者Willicious

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 10:04:30