Reputation: 682
I have the following code to display a number of labels in a panel :
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));
}
As it is everything works fine :
Now, I don't really have a use for 7 and 7bis, I just added them to show you what I want. So lets remove them :
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));
}
Now I get this monstrosity :
The height on number 3 and 4 are no longer taken into account, everything is of same height.
Why is this happening ? How can I force the layout to obey me :( ?
Upvotes: 2
Views: 402
Reputation: 347204
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 ?
You have somewhat of a misunderstanding in how GridBagLayout
works
So, your original layout looks something like this...
Cells 1x1
(3
) and 2x1
(4
) are actually oversized, their heights are a sum of the heights of rows 1
and 2
Then you remove the cells at 3x0
and 3x1
and you have the expectation of something like this...
But, wait, GridBagLayout
is clever, it's deduced that, because of the row spans, row 1 is actually empty (has a combined size of 0) so it compresses the row and you end up with...
You might think this is "wrong", but it's not, and it takes some time to think about what's actually happening.
The only cell which is actually has any affect on the height of row 1
is cell 3x1
, which technically now has a size of 0
, because nothing resides there, so the row height becomes, 0
(also the preferred height of the cells @ 1x1
and 1x2
are smaller than the sum of the two rows the span from before, it has an affect as well)
So GridBagLayout
looks at cells 1x1
(3
) and 2x1
(4
) and calculates their heights as a sum of the heights of rows 1
and 2
, but because 0
plus anything is anything, the row is "collapsed" and GridBagLayout
relies on the preferred/minimum/maximum
size of the components to determine the actual height to be used.
Now, I know, you're going to complain that this doesn't make sense, because cells 1x1
(3
) and 2x1
(4
) start in row 1
, and their height should affect the height of the row and everything, in some sense they do, but then they also expand two rows, which in the mind of GridBagLayout
has an effect on the outcome, this is just how GridBagLayout
works.
So, what's the solution? Like it or not, if you want the layout NOT to compress, you need to supply some kind of component at 3x2
which has the desired height of the row. I know, it's not a great solution and I've done a lot of different hacks in the past to make it work (using a JLabel
whose foreground color was the same as the background color of the container, or which had a foreground color which was completely transparent. I've even used my own layout manager which ignored the visible
property of the component to cause it to keep the container at the the same size, so I could "hide" and "show" the component without having the layout compress)
Another solution might be to investigate other layout managers, I recommend MigLayout as a starting point.
Now, again, before you complain about it "not making sense" or "not be right" or "it must be bug" - Remember, this is how GridBagLayout
has worked for the past 20+ years - this is how it works - you need to understand it and work with it or find an alternative - sorry to be a pain about that, but that's just the way it is :(
Upvotes: 4