JFrame.getInsets奇怪的值

时间:2020-09-10 11:43:51

标签: java swing java-11

在Windows 10上采用OpenJDK11。JFrame后代构造函数:

getGraphicsConfiguration().getBounds()
java.awt.Rectangle[x=0,y=0,width=2560,height=1440]

Toolkit.getDefaultToolkit().getScreenInsets(getGraphicsConfiguration())
java.awt.Insets[top=0,left=0,bottom=40,right=0]

set*Size(new Dimension(2560, 1400));

pack();

getSize();
java.awt.Dimension[width=2560,height=1400]

getInsets();
java.awt.Insets[top=31,left=8,bottom=8,right=8]

getContentPane().getSize()
java.awt.Dimension[width=2544,height=1361]

...但是该窗口没有覆盖桌面空间减去任务栏(因为这些额外的插图8)。为什么?

使用我的答案的示例代码:

package javaapplication2;

import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GraphicsConfiguration;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.Toolkit;
import javax.swing.JFrame;
import javax.swing.JPanel;

public final class TestFrame extends JFrame {

    private static final long serialVersionUID = 1L;

    private static final class CustomPanel extends JPanel {

        private static final long serialVersionUID = 1L;

        public CustomPanel(Dimension d) {
            setMinimumSize(d);
            setPreferredSize(d);
            setMaximumSize(d);
            //this is just an example, there is custom layout code here, not using Swing, but it needs Dimension d to work
        }

    }

    public TestFrame() {
        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        getContentPane().setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0));

        GraphicsConfiguration gc = getGraphicsConfiguration();
        Rectangle screenBounds = gc.getBounds();
        Insets screenInsets = Toolkit.getDefaultToolkit().getScreenInsets(gc);
        Dimension expectedFrameSize = new Dimension(screenBounds.width - screenInsets.left - screenInsets.right, screenBounds.height - screenInsets.top - screenInsets.bottom);

        setExtendedState(JFrame.MAXIMIZED_BOTH);
        setVisible(true);
        Dimension frameSize = getSize();
        Insets frameInsets = getInsets();
        setVisible(false);
        Dimension contentSize = new Dimension(frameSize.width - frameInsets.left - frameInsets.right, frameSize.height - frameInsets.top - frameInsets.bottom);
        getContentPane().add(new CustomPanel(contentSize));

        setVisible(true);
        setResizable(false);

        System.out.println("screenBounds " + screenBounds);
        System.out.println("screenInsets " + screenInsets);
        System.out.println("expectedFrameSize " + expectedFrameSize);
        System.out.println("frameSize " + frameSize);
        System.out.println("frameInsets " + frameInsets);
        System.out.println("contentSize " + contentSize);
        System.out.println("assert expectedFrameSize == frameSize " + expectedFrameSize.equals(frameSize));
    }

    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                new TestFrame().setVisible(true);
            }
        });
    }

}

我希望能够在不使窗口暂时可见的情况下计算Dimension dimension。但是使用JDK中可用的方法来达到正确的大小是不可能的:

getGraphicsConfiguration().getBounds()
Toolkit.getDefaultToolkit().getScreenInsets(getGraphicsConfiguration())

2 个答案:

答案 0 :(得分:2)

框架的插图描述了窗户装饰的大小,其中可能包括半透明的边框。在Microsoft Windows上,还与以下事实有关:在早期版本中,窗口边框的厚度为8像素。

当您最大化窗口时,其边界的设置将使这些插图位于可见区域之外,但标题栏的某些部分保持可见。为了使可预测性更加糟糕,当窗口最大化时,标题栏会更改其布局,而空白空间较小。

但是,当您在寻找仅Windows的解决方案时,遗留方面可能会有所帮助。考虑一下文章“ Why does a maximized window have the wrong window rectangle?。如其解释,该窗口将始终位于(- n ,- n )并具有(2 n ×2 n < / em>),而不是实际可见区域(边框大小 n ),以便与旧软件兼容。但是,正如它还解释的那样,最大化模式是特殊的,因为这些边界始终会被切除,因此它们不会显示在其他监视器中或任务栏上。

这就是为什么不可能仅通过设置边界来模仿相同的行为。标题栏的呈现方式不仅有所不同,而且还使窗口的一部分出现在多显示器系统上的其他显示器中以及任务栏上方。

因此,利用这些知识,您可以预测内容窗格的大小:

JFrame frame = new JFrame("Max");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setExtendedState(Frame.MAXIMIZED_BOTH);

Timer t = new Timer(1000, ev -> System.out.println("actual size is "
    +frame.getContentPane().getWidth()+" x "+frame.getContentPane().getHeight()));
t.setRepeats(false);
t.start();

Rectangle scrBounds = frame.getGraphicsConfiguration().getBounds();
Insets scrInsets = frame.getToolkit().getScreenInsets(frame.getGraphicsConfiguration());
Insets winInsets = frame.getInsets();

int width = scrBounds.width - scrInsets.left - scrInsets.right;
int height = scrBounds.height - scrInsets.top - scrInsets.bottom
                              - winInsets.top + winInsets.bottom;

System.out.println("content pane size will be "+width+" x "+height);

frame.setVisible(true);

这假定历史边框的所有边缘的厚度均相同,因此我们可以使用bottom的大小来确定标题栏大小的顶部大小,因此top - bottom为我们提供剩余的标题条尺寸。

答案 1 :(得分:0)

显然最大化的帧的尺寸大于实际屏幕,并且帧插图包括8,8,8,8像素(在我的Windows上),其中一些像素不在实际帧范围内。获取用于最大化窗口的实际帧大小的唯一方法是使其可见一会儿。最后,我诉诸于此作弊:


public class Driver {
        static String first;
        static String middle;
        static String last;


        public static void main(String[] args){
                Student student1 = new Student(first, middle, last);
                student1.setFirst("Mikayla");
                student1.setMiddle("Rose");
                student1.setLast("Knox");


        }
}

这使我能够找出框架内容窗格的尺寸,其中框架占据所有桌面空间(屏幕减去任务栏)。并且 setExtendedState(JFrame.MAXIMIZED_BOTH); setVisible(true); Dimension size = getSize(); Insets insets = getInsets(); setVisible(false); dimension = new Dimension(size.width - insets.left - insets.right, size.height - insets.top - insets.bottom); 仅在最后setResizable(false)之后才被调用。

看看这些数字对您是否有意义:

屏幕边界setVisible(true)

屏幕插图java.awt.Rectangle[x=0,y=0,width=2560,height=1440]

帧大小java.awt.Insets[top=0,left=0,bottom=40,right=0]

帧插入java.awt.Dimension[width=2576,height=1416]

计算尺寸java.awt.Insets[top=31,left=8,bottom=8,right=8]

帧大小在每个方向上比屏幕空间(屏幕边界减去屏幕插图)大16。而且那些多余的像素也包含在帧插图中,即使它们不在帧中。