Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/398.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 为什么进入全屏时在JFrame中设置首选大小失败?_Java_Swing_Layout Manager - Fatal编程技术网

Java 为什么进入全屏时在JFrame中设置首选大小失败?

Java 为什么进入全屏时在JFrame中设置首选大小失败?,java,swing,layout-manager,Java,Swing,Layout Manager,我想为实际屏幕创建一个具有固定宽度/高度比的游戏(这样我就可以轻松地缩放游戏元素,而不必担心复杂的布局)。为此,我创建了一个JFrame,带有一个BorderLayout,实际屏幕在中间,4个间隔面板在侧面。每次调整大小后,我都会重新计算所需的间距,并相应地设置首选尺寸,这样屏幕就可以获得适合框架的给定比率的最大角度。下面的代码完成了这项工作,我用一个简单的蓝色面板替换了实际屏幕,并添加了输出以检查计算: import java.awt.BorderLayout; import java.awt

我想为实际屏幕创建一个具有固定宽度/高度比的游戏(这样我就可以轻松地缩放游戏元素,而不必担心复杂的布局)。为此,我创建了一个
JFrame
,带有一个
BorderLayout
,实际屏幕在中间,4个间隔面板在侧面。每次调整大小后,我都会重新计算所需的间距,并相应地设置首选尺寸,这样屏幕就可以获得适合框架的给定比率的最大角度。下面的代码完成了这项工作,我用一个简单的蓝色面板替换了实际屏幕,并添加了输出以检查计算:

import java.awt.BorderLayout;
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;
import javax.swing.SwingUtilities;

public class JFrameResize {
  private static JFrame frame;
  private static JPanel inside = new JPanel();
  private static JPanel spacingTop = new JPanel();
  private static JPanel spacingBottom = new JPanel();
  private static JPanel spacingLeft = new JPanel();
  private static JPanel spacingRight = new JPanel();
  private static JPanel compound = new JPanel();

  public static void main(String[] args) {
    SwingUtilities.invokeLater(() -> createAndShowGUI());
  }

  public static void createAndShowGUI() {
    frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    inside.setBackground(Color.BLUE);
    compound.setLayout(new BorderLayout());
    compound.add(inside, BorderLayout.CENTER);
    compound.add(spacingTop, BorderLayout.NORTH);
    compound.add(spacingBottom, BorderLayout.SOUTH);
    compound.add(spacingLeft, BorderLayout.WEST);
    compound.add(spacingRight, BorderLayout.EAST);

    frame.add(compound);

    frame.addComponentListener(new ComponentAdapter() {
      @Override
      public void componentResized(ComponentEvent e) {
        calculateSize();
      }
    });

    calculateSize();
    frame.setVisible(true);
  }

  public static void calculateSize() {
    double width = frame.getContentPane().getWidth();
    double height = frame.getContentPane().getHeight();
    double vSpacing = 0, hSpacing = 0;

    System.out.println("frame: " + width + ":" + height);

    // ratio is hardcoded to 3:4
    if ((width * 3 - height * 4) >= 0) {
      hSpacing = (width - (height * 4) / 3) / 2;
      width = width - 2 * hSpacing;
    } else {
      vSpacing = (height - (width * 3) / 4) / 2;
      height = height - 2 * vSpacing;
    }

    System.out.println("spacing: " + hSpacing + " + " + width + " + " + hSpacing + "  :  "
        + vSpacing + " + " + height + " + " + vSpacing);

    spacingBottom.setPreferredSize(new Dimension((int) width, (int) vSpacing));
    spacingTop.setPreferredSize(new Dimension((int) width, (int) vSpacing));
    spacingLeft.setPreferredSize(new Dimension((int) hSpacing, (int) height));
    spacingRight.setPreferredSize(new Dimension((int) hSpacing, (int) height));
    inside.setPreferredSize(new Dimension((int) width, (int) height));

    frame.revalidate();
    frame.repaint();

    System.out.println("inside: " + inside.getWidth() + ":" + inside.getHeight()
      + ", " + "border: " + spacingLeft.getWidth() + ":"
      + spacingTop.getHeight());
  }
}
这在大多数情况下都很有效,我的输出如下

帧:510.0:445.0
间距:0.0+510.0+0.0:31.25+382.5+31.25
内部:510:385,边界:0:30

框架显示正确的矩形。但是,如果将帧设置为全屏,则会得到以下输出:

帧:1366.0:705.0
间距:213.0+940.0+213.0:0.0+705.0+0.0
内部:1366:643,边界:0:31

这是不正确的,因为我的公式计算的内部是940:705,但它变成了1312:705。矩形也不再正确显示。使用windows+箭头键或将框架拖动到屏幕两侧也是如此。计算输入是正确的,但重新绘制/重新验证的行为与正常的调整大小不同。
revalidate()
repaint()
的不同组合,或者在代码中滥发它们似乎不会改变任何东西


这是如何发生的,我该如何解决?或者这种方法通常有缺陷,应该被替换?

不要使用边界布局,尝试添加间距组件

相反,我建议您可以将内容面板的布局管理器设置为
GridBagLayout
。使用默认的
GridBagConstraints
时,添加到
GridBagLayout
的任何组件将自动居中

然后,对于添加到框架中的“内部”面板,需要覆盖
getPreferredSize()
方法来计算面板的大小

要确定其首选大小,您需要获取其父容器的大小,然后根据规则确定其首选大小

不需要ComponentListener,因为只要调整框架的大小,就会自动调用布局管理器

让您开始学习的简单示例:

import java.awt.*;
import javax.swing.*;

public class JFrameResize
{
  public static void main(String[] args) {
    SwingUtilities.invokeLater(() -> createAndShowGUI());
  }

  public static void createAndShowGUI() {
    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    JPanel inside = new JPanel()
    {
        @Override
        public Dimension getPreferredSize()
        {
            Dimension parent = getParent().getSize();
            Dimension child = new Dimension();

            int value = (parent.width * 3) - (parent.height * 4);

            if (value > 0)
            {
                child.height = parent.height;
                child.width = (int)(child.height * 4 / 3);
            }
            else
            {
                child.width = parent.width;
                child.height = (int)(child.width * 3 / 4);
            }

            return child;
        }
    };

    inside.setBackground(Color.BLUE);

    frame.setLayout( new GridBagLayout() );
    frame.add(inside, new GridBagConstraints());
    frame.pack();
    frame.setVisible(true);
  }
}

不要使用边界布局并尝试添加间距组件

相反,我建议您可以将内容面板的布局管理器设置为
GridBagLayout
。使用默认的
GridBagConstraints
时,添加到
GridBagLayout
的任何组件将自动居中

然后,对于添加到框架中的“内部”面板,需要覆盖
getPreferredSize()
方法来计算面板的大小

要确定其首选大小,您需要获取其父容器的大小,然后根据规则确定其首选大小

不需要ComponentListener,因为只要调整框架的大小,就会自动调用布局管理器

让您开始学习的简单示例:

import java.awt.*;
import javax.swing.*;

public class JFrameResize
{
  public static void main(String[] args) {
    SwingUtilities.invokeLater(() -> createAndShowGUI());
  }

  public static void createAndShowGUI() {
    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    JPanel inside = new JPanel()
    {
        @Override
        public Dimension getPreferredSize()
        {
            Dimension parent = getParent().getSize();
            Dimension child = new Dimension();

            int value = (parent.width * 3) - (parent.height * 4);

            if (value > 0)
            {
                child.height = parent.height;
                child.width = (int)(child.height * 4 / 3);
            }
            else
            {
                child.width = parent.width;
                child.height = (int)(child.width * 3 / 4);
            }

            return child;
        }
    };

    inside.setBackground(Color.BLUE);

    frame.setLayout( new GridBagLayout() );
    frame.add(inside, new GridBagConstraints());
    frame.pack();
    frame.setVisible(true);
  }
}

关于我的方法不起作用的原因:

发自(感谢@Andrew Thompson的链接)声明:

[setPreferredSize]被LayoutManager用作平衡实际布局的提示


因此,我的
setPreferredSize
可能被
BorderLayout
覆盖,为了确保
LayoutManager
不会干扰,您必须覆盖
getPreferredSize

,了解我的方法不起作用的原因:

发自(感谢@Andrew Thompson的链接)声明:

[setPreferredSize]被LayoutManager用作平衡实际布局的提示

因此,我的
setPreferredSize
可能被
BorderLayout
覆盖,为了确保
LayoutManager
不会干扰,您必须覆盖
getPreferredSize

“设置首选大小”请参见(是)。“设置首选大小”请参见(是)