为什么 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
的工作原理有些误解
所以,您的原始布局看起来像这样...
单元格1x1
(3
)和2x1
(4
)实际上超大了,它们的高度是1
行高度的总和和 2
然后您删除 3x0
和 3x1
处的单元格,您会期望得到这样的结果...
但是,等等,GridBagLayout
很聪明,它推断出,由于行跨度,第 1 行实际上是空的(组合大小为 0)所以它压缩了该行,你最终得到...
您可能认为这是 "wrong",但事实并非如此,并且需要一些时间来思考实际发生的事情。
唯一实际对行 1
的高度有任何影响的单元格是单元格 3x1
,从技术上讲,它现在的大小为 0
,因为那里没有任何东西,所以行高变成 0
(单元格的首选高度@ 1x1
和 1x2
小于之前跨度的两行的总和,它的影响是嗯)
因此 GridBagLayout
查看单元格 1x1
(3
) 和 2x1
(4
) 并将它们的高度计算为高度的总和行 1
和 2
,但因为 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 多年中的工作方式- 这就是它的工作原理 - 你需要理解它并使用它或找到替代方案 - 很抱歉为此感到痛苦,但这就是它的方式:(
我有以下代码可以在面板中显示多个标签:
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
的工作原理有些误解
所以,您的原始布局看起来像这样...
单元格1x1
(3
)和2x1
(4
)实际上超大了,它们的高度是1
行高度的总和和 2
然后您删除 3x0
和 3x1
处的单元格,您会期望得到这样的结果...
但是,等等,GridBagLayout
很聪明,它推断出,由于行跨度,第 1 行实际上是空的(组合大小为 0)所以它压缩了该行,你最终得到...
您可能认为这是 "wrong",但事实并非如此,并且需要一些时间来思考实际发生的事情。
唯一实际对行 1
的高度有任何影响的单元格是单元格 3x1
,从技术上讲,它现在的大小为 0
,因为那里没有任何东西,所以行高变成 0
(单元格的首选高度@ 1x1
和 1x2
小于之前跨度的两行的总和,它的影响是嗯)
因此 GridBagLayout
查看单元格 1x1
(3
) 和 2x1
(4
) 并将它们的高度计算为高度的总和行 1
和 2
,但因为 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 多年中的工作方式- 这就是它的工作原理 - 你需要理解它并使用它或找到替代方案 - 很抱歉为此感到痛苦,但这就是它的方式:(