为什么 GridBagLayout 会在我的组件上施加一些高度?

Why is the GridBagLayout forcing some height on my components?

我有以下代码可以在面板中显示多个标签:

    private static class Bordered extends JLabel {
        public Bordered(final String text) {
            super(text);
            this.setBorder(new MatteBorder(2,2,2,2,Color.BLACK));
        }
    }

    public static void main(String[] args) {
        Frame frame = new Frame("toto");

        JPanel panel = new JPanel(new GridBagLayout());
        panel.add(new Bordered("0"), new GridBagConstraints(0,0,1,3, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(3, 3, 3, 3), 0, 0));
        panel.add(new Bordered("1"), new GridBagConstraints(1,0,1,1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(3, 3, 3, 3), 0, 0));
        panel.add(new Bordered("2"), new GridBagConstraints(2,0,1,1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(3, 3, 3, 3), 0, 0));
        panel.add(new Bordered("3"), new GridBagConstraints(1,1,1,2, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(3, 3, 3, 3), 0, 0));
        panel.add(new Bordered("4"), new GridBagConstraints(2,1,1,2, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(3, 3, 3, 3), 0, 0));
        panel.add(new Bordered("5"), new GridBagConstraints(3,2,1,1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(3, 3, 3, 3), 0, 0));
        panel.add(new Bordered("6"), new GridBagConstraints(4,0,1,3, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(3, 3, 3, 3), 0, 0));
        panel.add(new Bordered("7"), new GridBagConstraints(3,0,1,1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(3, 3, 3, 3), 0, 0));
        panel.add(new Bordered("7bis"), new GridBagConstraints(3,1,1,1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(3, 3, 3, 3), 0, 0));


        frame.add(panel);

        frame.pack();
        SwingUtilities.invokeLater(() -> frame.setVisible(true));
    }

一切正常:

现在,我并没有真正使用 7 和 7bis,我只是添加它们来向您展示我想要的东西。所以让我们删除它们:

    private static class Bordered extends JLabel {
        public Bordered(final String text) {
            super(text);
            this.setBorder(new MatteBorder(2,2,2,2,Color.BLACK));
        }
    }

    public static void main(String[] args) {
        Frame frame = new Frame("toto");

        JPanel panel = new JPanel(new GridBagLayout());
        panel.add(new Bordered("0"), new GridBagConstraints(0,0,1,3, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(3, 3, 3, 3), 0, 0));
        panel.add(new Bordered("1"), new GridBagConstraints(1,0,1,1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(3, 3, 3, 3), 0, 0));
        panel.add(new Bordered("2"), new GridBagConstraints(2,0,1,1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(3, 3, 3, 3), 0, 0));
        panel.add(new Bordered("3"), new GridBagConstraints(1,1,1,2, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(3, 3, 3, 3), 0, 0));
        panel.add(new Bordered("4"), new GridBagConstraints(2,1,1,2, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(3, 3, 3, 3), 0, 0));
        panel.add(new Bordered("5"), new GridBagConstraints(3,2,1,1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(3, 3, 3, 3), 0, 0));
        panel.add(new Bordered("6"), new GridBagConstraints(4,0,1,3, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(3, 3, 3, 3), 0, 0));
//        panel.add(new Bordered("7"), new GridBagConstraints(3,0,1,1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(3, 3, 3, 3), 0, 0));
//        panel.add(new Bordered("7bis"), new GridBagConstraints(3,1,1,1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(3, 3, 3, 3), 0, 0));


        frame.add(panel);

        frame.pack();
        SwingUtilities.invokeLater(() -> frame.setVisible(true));
    }

现在我明白了这个怪物:

不再考虑数字 3 和 4 的高度,所有高度相同。

为什么会这样?我怎样才能强制布局服从我:(?

Number 5's contract is to be 1 by 1 and at the 3rd row. This contract is clearly NOT being followed by the layout here. How can number 4 and number 5 have the same height, or even be in the same position, when their y and height attributes are different ?

您对GridBagLayout的工作原理有些误解

所以,您的原始布局看起来像这样...

单元格1x13)和2x14)实际上超大了,它们的高度是1行高度的总和和 2

然后您删除 3x03x1 处的单元格,您会期望得到这样的结果...

但是,等等,GridBagLayout 很聪明,它推断出,由于行跨度,第 1 行实际上是空的(组合大小为 0)所以它压缩了该行,你最终得到...

您可能认为这是 "wrong",但事实并非如此,并且需要一些时间来思考实际发生的事情。

唯一实际对行 1 的高度有任何影响的单元格是单元格 3x1,从技术上讲,它现在的大小为 0,因为那里没有任何东西,所以行高变成 0(单元格的首选高度@ 1x11x2 小于之前跨度的两行的总和,它的影响是嗯)

因此 GridBagLayout 查看单元格 1x1 (3) 和 2x1 (4) 并将它们的高度计算为高度的总和行 12,但因为 0 加上任何东西,行是 "collapsed" 和 GridBagLayout 依赖于 preferred/minimum/maximum 的大小组件来确定要使用的实际高度。

现在,我知道,你会抱怨这没有意义,因为单元格 1x1 (3) 和 2x1 (4 ) 从行 1 开始,它们的高度应该影响行的高度和所有内容,在某种意义上它们确实如此,但随后它们也扩展了两行,这在 GridBagLayout 的思想中有影响关于结果,这就是 GridBagLayout 的工作方式。

那么,解决方案是什么?不管你喜不喜欢,如果你不想压缩布局,你需要在 3x2 处提供某种具有所需行高的组件。我知道,这不是一个很好的解决方案,过去我做了很多不同的黑客来让它工作(使用 JLabel 其前景颜色与容器的背景颜色相同,或者有一种完全透明的前景色。我什至使用了我自己的布局管理器,它忽略了组件的 visible 属性 以使其保持容器大小相同,所以我可以 "hide" 和 "show" 没有布局压缩的组件)

另一种解决方案可能是调查其他布局管理器,我建议以 MigLayout 作为起点。

现在,再一次,在你抱怨它之前 "not making sense" 或 "not be right" 或 "it must be bug" - 请记住,这就是 GridBagLayout 在过去 20 多年中的工作方式- 这就是它的工作原理 - 你需要理解它并使用它或找到替代方案 - 很抱歉为此感到痛苦,但这就是它的方式:(