【问题标题】:Using a JPanel inside JFrame does not size or move correctly在 JFrame 中使用 JPanel 无法正确调整大小或移动
【发布时间】:2012-11-03 09:39:59
【问题描述】:

感谢您花时间阅读本文。我希望它不会混淆,如果需要任何其他信息,请告诉我!

问题: 我正在制作一个类似蛇的游戏,我创建了一个 JFrame,然后添加了 JPanel。好吧,如果我不在 JFrame 中设置它的大小,它将大小约为 100 x 20。当我设置它的大小时,它保持在设置的尺寸。但是,如果我 pack() 它,当我在 JPanel 中定义大小时,它会缩小到 100 x 20 左右。我也设定了界限,没有运气。我使用 FlowLayout() 和 BorderLayout() 也没有成功。现在我的游戏运行正常并且没有问题,除了框架。它会切断两侧,除非我做一些我不想做的体操。

目标: 我希望能够将帧大小正确地设置为我指定的宽度和高度,并让面板向下移动一点以为游戏的文本添加空间,这样它就不会阻塞任何东西。

基本上我很困惑和慌乱,我花了几天时间做这件事,到目前为止我还没有成功。

JFrame 类:

public class main extends JFrame {

 /**
  * @param args the command line arguments
  */

 public main(){
     Board game = new Board();

     setLayout(new BorderLayout(0, 50));
     setSize(game.getGameWidth(), game.getGameHeight());
     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
     setLocationRelativeTo(null);
     setTitle("BlockRunner");
     getContentPane().add(game);

     setResizable(false);
     setVisible(true);
 }
}

我的董事会课程:

public class Board extends JPanel implements ActionListener, KeyListener{
 private int width = 600;
 private int height = 400;
 Board(){
     addKeyListener(this);
     setFocusable(true);
     setBackground(Color.LIGHT_GRAY);
     setSize(width, height);
     InitGame();
 }
}

我愿意尝试任何有人愿意为我提供的东西。 感谢您的宝贵时间!

编辑1:(由于用户的回答。) 使用 setPerferredSize()、setMinmumSize() 和 setMaximumSize() 不会影响结果。

【问题讨论】:

  • 你试过 setPreferedSize() 吗?

标签: java swing jframe jpanel sizing


【解决方案1】:

我知道你说使用setPreferredSize() 不会影响结果,但我和另外两个人似乎认为应该解决它。您可以尝试以下方法吗:

主要改动如下:

setSize(game.getGameWidth(), game.getGameHeight());

收件人:

setPreferredSize(new Dimension(game.getGameWidth(), game.getGameHeight()));

然后添加pack(),看看结果有没有变化。从理论上讲,这应该可以解决问题,除非发生了我们看不到的其他事情。

【讨论】:

【解决方案2】:

假设Board 主要用于绘图,您可以覆盖getPreferredSize() 以返回合适的Dimension。当您pack() 封闭Window 时,它将采用选择的大小。请参阅此Q&A 了解更多信息,并避免使用此pitfall

【讨论】:

  • 在这个相关的answer中也可以看到center
  • 棋盘基本上是用来控制游戏的。非常感谢您的帮助!它帮助并让我更深入地了解编写 Java GUI。
【解决方案3】:

我更喜欢使用 swing 的方式是让内部组件设置它们的首选大小, 并拥有 JFrame 包。

所以你总共需要:

  • 移除 JFrame 中的 setSize(或更改为 setPreferredSize)
  • 将 JPanel 中的 setSize 更改为 setPreferredSize。
  • 一切完成后在 JFrame 中调用包。

看看下面的代码是否符合你的要求。

public class Main extends JFrame {

    public Main() {
        Board game = new Board();

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        {
            Container contentPane = getContentPane();
            contentPane.setLayout(new BorderLayout(0, 50));
            JLabel label = new JLabel("hello world!");
            contentPane.add(label, BorderLayout.NORTH);
            contentPane.add(game, BorderLayout.CENTER);
        }
        pack();

        setResizable(false);
        setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new Main();
            }
        });
    }
}

public class Board extends JPanel {
    private int width = 600;
    private int height = 400;

    Board() {
        setFocusable(true);
        setBackground(Color.LIGHT_GRAY);
        setPreferredSize(new Dimension(width, height));
    }

}

【讨论】:

  • 谢谢你的链接,但这些都是他个人的感觉,不是吗。首选尺寸仅作为布局管理器的“指南”存在。有一次我实现了自己的布局管理器,我可以选择忽略首选大小或使用它。他们真的没有错。
  • 与其说是 kleopatra 的个人感受,不如说是长期实现组件库的经验,以及看到setXxxSize() 被滥用。遗憾的是,Twister1002 要求我们猜测为什么 Board 未能合理回应 pack()
  • @trashgod 我不是在要求猜测。我已经尝试了所有这些组合,因为它没有给我任何帮助或差异。我非常感谢这个链接!
  • @Twister1002:您的Board 不包含任何组件,因此MadP 的BoardGamePane 是一种合理的方法。
【解决方案4】:

您需要结合使用getPreferred/Minimum/MaximumSize 和真正尊重它的布局。

在这里,我使用了GridBagLayout 设置,以便电路板始终保持相同大小,但单元格将使用最大数量的相同。

如果您想将文本保留在板的底部(而不是框架),请删除 weighty 约束(可能还有 weightx

public class TestBoardGame {

    public static void main(String[] args) {
        new TestBoardGame();
    }

    public TestBoardGame() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException ex) {
                } catch (InstantiationException ex) {
                } catch (IllegalAccessException ex) {
                } catch (UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Test");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new GridBagLayout());

                GridBagConstraints gbc = new GridBagConstraints();
                gbc.gridx = 0;
                gbc.gridy = 0;
                gbc.weightx = 1;
                gbc.weighty = 1;
                frame.add(new BoardGamePane(), gbc);

                gbc.gridx = 0;
                gbc.gridy = 1;
                gbc.weightx = 1;
                gbc.fill= GridBagConstraints.HORIZONTAL;
                JLabel text = new JLabel("Area for text");
                text.setHorizontalAlignment(JLabel.CENTER);
                frame.add(text, gbc);

                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }

        });
    }

    public class BoardGamePane extends JPanel {

        public BoardGamePane() {

            setBorder(new LineBorder(Color.RED));
            setBackground(Color.ORANGE);

        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(400, 300);
        }

        @Override
        public Dimension getMinimumSize() {
            return getPreferredSize();
        }

        @Override
        public Dimension getMaximumSize() {
            return getPreferredSize();
        }

    }    
}

【讨论】:

  • 你的代码比你的文本更好......如果你做自定义绘画,覆盖getPreferredSize比调用setPreferredSize好得多
  • @MadProgrammer 感谢您发布此消息!非常有助于理解垃圾神提到的内容
  • 感谢您的解决方案。尽管经过一番深思熟虑后,我意识到我的程序并不是为了能够在 JFrame 中写入数据而设计的(跟我一起去吧)。我希望将一些 g.drawString() 移动到 -15 以推高文本。这会更容易。然而,我开始思考它并意识到我是多么愚蠢。应用程序无法做到这一点! xD。但你的方法对我有用。谢谢!
猜你喜欢
  • 2012-06-21
  • 1970-01-01
  • 1970-01-01
  • 2012-09-01
  • 2013-10-11
  • 2012-05-16
  • 1970-01-01
相关资源
最近更新 更多