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

Linux Gnome下JFrame缩放保持16:9宽高比异常问题求助

Linux Gnome下JFrame保持16:9宽高比的问题修复

在Linux Gnome环境中开发时,若要让JFrame窗口保持16:9宽高比(调整宽度时仅修改高度,调整高度时仅修改宽度,保留用户输入的尺寸维度),原代码存在触发循环调整、未区分窗口边框与内容区的问题,导致调整宽度后高度异常变大。

原问题代码

import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Main
{
    public static void main(String[] args)
    {
        JPanel panel = new JPanel();
        panel.setPreferredSize(new Dimension(1280, 720));
        panel.setBackground(new Color(89, 108, 171, 255));

        JFrame frame = new JFrame("Test");
        frame.setLocation(100, 100);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(panel);
        frame.pack();
        frame.setVisible(true);

        panel.addComponentListener(new ComponentAdapter()
        {
            @Override
            public void componentResized(ComponentEvent e)
            {
                int targetWidth = frame.getSize().width;
                int targetHeight = frame.getSize().width * 9 / 16;

                if (targetHeight > frame.getSize().height)
                {
                    targetHeight = frame.getSize().height;
                    targetWidth = frame.getSize().height * 16 / 9;
                }

                frame.setSize(targetWidth, targetHeight);
            }
        }); 
    }
}

问题分析

  1. 循环触发事件:调用frame.setSize()会再次触发componentResized事件,导致反复调整尺寸,最终出现异常放大。
  2. 未区分窗口边框:frame.getSize()返回的是窗口整体尺寸(包含边框),直接用这个值计算比例会导致内容区尺寸不符合预期。
  3. 逻辑判断不合理:未区分用户是调整宽度还是高度,强制以某一维度为准,不符合“保留用户输入尺寸”的需求。

修复后的代码

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Main {
    private static boolean isResizing = false; // 防止循环触发事件

    public static void main(String[] args) {
        JPanel panel = new JPanel();
        panel.setPreferredSize(new Dimension(1280, 720));
        panel.setBackground(new Color(89, 108, 171, 255));

        JFrame frame = new JFrame("Test");
        frame.setLocation(100, 100);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(panel);
        frame.pack();
        frame.setVisible(true);

        frame.addComponentListener(new ComponentAdapter() {
            @Override
            public void componentResized(ComponentEvent e) {
                if (isResizing) return;
                isResizing = true;

                Insets insets = frame.getInsets();
                // 分离窗口边框与内容区尺寸
                int contentWidth = frame.getWidth() - insets.left - insets.right;
                int contentHeight = frame.getHeight() - insets.top - insets.bottom;

                // 计算两种维度下的理想尺寸
                int idealHeightFromWidth = contentWidth * 9 / 16;
                int idealWidthFromHeight = contentHeight * 16 / 9;

                // 判断用户调整方向:保留用户改动的维度
                int widthDiff = Math.abs(contentWidth - idealWidthFromHeight);
                int heightDiff = Math.abs(contentHeight - idealHeightFromWidth);

                int newContentWidth, newContentHeight;
                if (widthDiff < heightDiff) {
                    // 用户调整了宽度,以宽度为准计算高度
                    newContentWidth = contentWidth;
                    newContentHeight = idealHeightFromWidth;
                } else {
                    // 用户调整了高度,以高度为准计算宽度
                    newContentHeight = contentHeight;
                    newContentWidth = idealWidthFromHeight;
                }

                // 计算窗口整体尺寸(含边框)
                int newFrameWidth = newContentWidth + insets.left + insets.right;
                int newFrameHeight = newContentHeight + insets.top + insets.bottom;

                frame.setSize(newFrameWidth, newFrameHeight);
                isResizing = false;
            }
        });
    }
}

关键修复点

  • 添加防循环标志:isResizing变量避免调整尺寸时重复触发事件,打断无限循环。
  • 区分边框与内容区:用getInsets()获取边框尺寸,确保比例计算基于内容区实际大小。
  • 智能判断调整方向:通过尺寸差值判断用户的操作意图,优先保留用户调整的维度,再计算对应比例的另一维度,符合需求。
  • 监听窗口事件:直接监听JFrame的尺寸变化,而非内部面板,更准确捕捉窗口调整行为。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 14:47:31