如何避免调用pack()与setLocationByPlatform(true)后JFrame移出屏幕
问题描述
我有一个JFrame,使用pack()方法最小化框架内组件尺寸。但当组件过多时,启动窗口会接近屏幕大小;同时调用setLocationByPlatform(true)设置平台默认位置,两者结合会导致窗口部分移出屏幕。
我知晓多种变通方案,但希望排除全屏、禁用方法、手动设置尺寸位置等方案后,找到同时调用这两个方法且窗口完全显示在屏幕内的办法,允许内容被截断。
代码示例如下:
import javax.swing.*; public class SOQ_20231003 { public static void main(final String[] args) { SwingUtilities.invokeLater(SOQ_20231003::new); } public SOQ_20231003() { final JFrame frame = new JFrame(); frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); final JPanel panel = new JPanel(); for (int i = 0; i < 100; i++) { final JButton button = new JButton(); final String text = """ <html> <p> Totam qui nihil qui possimus architecto. Quo quia voluptatem possimus. Aliquid praesentium ab assumenda nisi eligendi eum dolore sed. Sint dolorem eaque est vitae ipsam architecto. Consectetur consequatur ipsum assumenda nostrum debitis ab a nobis. Dignissimos nobis rem aut nihil mollitia rerum. Porro quis neque eos. Dolorum eum sit aperiam cumque velit nulla quidem qui. Velit facilis maiores rerum mollitia. Tempore dolor consequatur quis. Similique minima animi et et repellat quam. Hic dolore voluptatem tempora est et dolor atque dolores. Odio est repellendus fugiat neque ut quas sunt quia. Sunt ea ab qui. Placeat pariatur dolores quis earum exercitationem. Nulla aut id nulla pariatur. Officia architecto sunt ipsum. Quo voluptatibus aut qui voluptates velit accusamus fuga. Beatae et ullam adipisci. Quo ducimus et in quam soluta officia ducimus. Placeat molestiae qui quia ut. Sint dolorem porro amet minus. Labore expedita dolorem omnis eveniet et quis. </p> </html> """ ; button.setText(text); panel.add(button); } frame.add(panel); frame.pack(); frame.setLocationByPlatform(true); frame.setVisible(true); // 窗口右侧内容被截断! } }
我意外这两个推荐方法会默认导致窗口移出屏幕,希望找到解决办法。
解决方案
核心思路是在窗口完成平台默认定位后,检查并调整其位置,确保完全落在屏幕的可用显示区域内,同时保留pack()和setLocationByPlatform(true)的原有逻辑。
修改后的代码如下:
import javax.swing.*; import java.awt.*; public class SOQ_20231003 { public static void main(final String[] args) { SwingUtilities.invokeLater(SOQ_20231003::new); } public SOQ_20231003() { final JFrame frame = new JFrame(); frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); final JPanel panel = new JPanel(); for (int i = 0; i < 100; i++) { final JButton button = new JButton(); final String text = """ <html> <p> Totam qui nihil qui possimus architecto. Quo quia voluptatem possimus. Aliquid praesentium ab assumenda nisi eligendi eum dolore sed. Sint dolorem eaque est vitae ipsam architecto. Consectetur consequatur ipsum assumenda nostrum debitis ab a nobis. Dignissimos nobis rem aut nihil mollitia rerum. Porro quis neque eos. Dolorum eum sit aperiam cumque velit nulla quidem qui. Velit facilis maiores rerum mollitia. Tempore dolor consequatur quis. Similique minima animi et et repellat quam. Hic dolore voluptatem tempora est et dolor atque dolores. Odio est repellendus fugiat neque ut quas sunt quia. Sunt ea ab qui. Placeat pariatur dolores quis earum exercitationem. Nulla aut id nulla pariatur. Officia architecto sunt ipsum. Quo voluptatibus aut qui voluptates velit accusamus fuga. Beatae et ullam adipisci. Quo ducimus et in quam soluta officia ducimus. Placeat molestiae qui quia ut. Sint dolorem porro amet minus. Labore expedita dolorem omnis eveniet et quis. </p> </html> """ ; button.setText(text); panel.add(button); } frame.add(panel); frame.pack(); frame.setLocationByPlatform(true); // 调整窗口位置,确保完全在屏幕可用区域内 adjustWindowToScreen(frame); frame.setVisible(true); } private void adjustWindowToScreen(Window window) { GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); Rectangle screenBounds = ge.getMaximumWindowBounds(); // 获取排除系统UI(如任务栏)的屏幕可用区域 Rectangle windowBounds = window.getBounds(); // 修正X坐标:避免窗口右边界超出屏幕,或左边界小于屏幕起始位置 int newX = windowBounds.x; if (windowBounds.x + windowBounds.width > screenBounds.x + screenBounds.width) { newX = screenBounds.x + screenBounds.width - windowBounds.width; } if (newX < screenBounds.x) { newX = screenBounds.x; } // 修正Y坐标:避免窗口下边界超出屏幕,或上边界小于屏幕起始位置 int newY = windowBounds.y; if (windowBounds.y + windowBounds.height > screenBounds.y + screenBounds.height) { newY = screenBounds.y + screenBounds.height - windowBounds.height; } if (newY < screenBounds.y) { newY = screenBounds.y; } // 仅当位置需要调整时更新 if (newX != windowBounds.x || newY != windowBounds.y) { window.setLocation(newX, newY); } } }
关键说明
getMaximumWindowBounds()会自动排除任务栏、dock等系统UI占用的空间,比直接获取屏幕整体尺寸更贴合实际可用区域。- 调整逻辑仅在窗口超出屏幕边界时生效,保留了
setLocationByPlatform(true)的平台默认定位行为,只是修正溢出问题。 - 未修改
pack()后的窗口尺寸,允许内容截断,符合需求限制。
内容的提问来源于stack exchange,提问作者davidalayachew
相关产品推荐
相关产品推荐

