使JPanel占据JFrame的整个宽度

3
我有两个JPanel需要放在一个JFrame中,我希望它们都占据整个窗口的宽度,但是我不知道如何设置。另外,我不太喜欢使用setBounds()方法,所以我想知道是否有一种方法可以使组件占满整个宽度,之后只需指定所需的高度即可。
这是我的代码:
public class Test extends JFrame {
    public Test() {

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(400, 400);
        setLocationRelativeTo(null);
        setLayout(new BorderLayout());

        JPanel header = new JPanel();
        header.setBounds(0,0,300,50);
        header.setLayout(new BorderLayout());
        header.setBackground(Color.gray);

        JPanel body = new JPanel();
        body.setBounds(0,50,300,300);
        body.setLayout(new BorderLayout());
        body.setBackground(Color.black);


        add(header, BorderLayout.NORTH);
        add(body, BorderLayout.CENTER);
        //setLayout(null);
        setVisible(true);


    }
}

1
这行代码 setLayout(null); 是无效的。 - Tom Hawtin - tackline
是的,谢谢,但是在移除它之后,我只看到了“正文”面板,头部不见了... - momodjib
使用 BorderLayout(这是 JFrame 的默认布局)通常可以实现此目的。您还可以使用 GridBagLayout,这可能会给您更多的控制权。问题在于,归根结底,像素完美的布局是一种幻觉。如果您“需要”限制组件的大小,则需要覆盖 getMinimum/Maximum/PreferredSize 方法。 - MadProgrammer
是的,谢谢,但是在移除它之后,我只看到了“body”面板,不再看到标题面板了。这是因为标题面板的默认大小是0x0 - MadProgrammer
那么就不要在body上调用setBounds()方法;只需要调用setPreferredSize()方法即可。 - FredK
2个回答

1
你需要移除 setLayout(null),因为这会撤销之前的 setLayout(new BorderLayout()) 的工作。
然后,你需要使用 setPreferredSize 设置标题和正文的首选大小,而不是使用 setBounds()
public Test() {
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setSize(400, 400);
    setLocationRelativeTo(null);
    setLayout(new BorderLayout());

    JPanel header = new JPanel();
    header.setPreferredSize(new Dimension(400, 50));
    header.setLayout(new BorderLayout());
    header.setBackground(Color.gray);

    JPanel body = new JPanel();
    body.setPreferredSize(new Dimension(400, 300));
    body.setLayout(new BorderLayout());
    body.setBackground(Color.black);

    add(header, BorderLayout.NORTH);
    add(body, BorderLayout.CENTER);
    setVisible(true);
}

感谢您的回答! - momodjib
我会谨慎使用 -1 作为此方式的大小 - 没有关于这样做会发生什么的文档记录,而其效果可能因平台/版本而异。实际上,在阅读 BorderLayout 的代码时,它只是将该值添加到其计算中,以确定其整体布局和各个组件的大小,这意味着它将尝试使组件宽度为 -1 像素。当我测试代码时(使用 pack 而不是 setSize),它生成了一个窗口,该窗口是系统允许的最小宽度。 - MadProgrammer

0
基本答案是,您需要利用布局管理框架。
布局管理器通过考虑组件的首选/最小/最大大小来工作 - 但要注意,这些仅是指南,布局管理器可能会根据其需求和可用空间忽略其中一些或全部。
以下是一个简单的示例,它覆盖了headergetPreferredSize方法以返回“理想”的大小:
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setLayout(new BorderLayout());

JPanel header = new JPanel() {
    @Override
    public Dimension getPreferredSize() {
        return new Dimension(300, 50);
    }

};
header.setLayout(new BorderLayout());
header.setBackground(Color.gray);

// I would allow the content of the panel determine the actual size
// but I've overridden `getPreferredSize` for demonstration purposes
JPanel body = new JPanel() {
    @Override
    public Dimension getPreferredSize() {
        return new Dimension(200, 200);
    }
};
body.setLayout(new BorderLayout());
body.setBackground(Color.black);

frame.add(header, BorderLayout.NORTH);
frame.add(body, BorderLayout.CENTER);
// pack is preferred over setSize, as it will "pack" the window around
// the content, which will produce a more consistent result
frame.pack();
frame.setVisible(true);

这样做的问题是,组件将不再考虑其子元素的大小要求,因此您可能会遇到一些奇怪的副作用。

还有其他解决方案,可能提供一些其他优缺点,您需要考虑它们是否适用于您的用例。

为什么要覆盖 getPreferredSize 而不是调用 setPreferredSize

主要是控制。您可以防止代码的其他部分修改状态,并控制“如何”进行计算。当然,没有什么能阻止其他代码扩展组件并覆盖该方法,但这更加复杂,并且不能考虑提供组件实例而不是创建组件的情况。

为什么使用 pack 而不是 setSize

pack 将窗口框架“包装”在内容周围,因此内容始终与其首选大小匹配,而不是缩小内容以容纳框架装饰。总体而言,在多个平台上生成更一致的结果。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接