In the GridBagLayout example that follows, all the panels nest nicely
within the frame with no spare space.
Now change the last three lines of the constructor
from
add(panel5, new GBC(3, 1, 1, GBC.REMAINDER));
//add(panel5, new GBC(3, 1, 1, GBC.RELATIVE));
//add(panel6, new GBC(3, 3, 1, 1));
to
//add(panel5, new GBC(3, 1, 1, GBC.REMAINDER));
add(panel5, new GBC(3, 1, 1, GBC.RELATIVE));
add(panel6, new GBC(3, 3, 1, 1));
Now there is a large blank area at the bottom of the frame. Can anyone
tell me why?
// MyApp9.java
import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
public class MyApp9 extends JPanel {
static final String[] lorem = { "lorem", "ipsum", "dolor", "sit",
"amet", "consectateur", "adipsicing", "elit", "sed",
"do", "euismod", "tempor", "incididunt", "ut", "labore",
"et", "dolore", "magna", "aliqua", "ut", "enim", "ad",
"minim", "veniam", "quis", "nostrud", "exertitation",
"ullamco", "laboris", "nisi", "ut", "aliquip", "ex",
"ea", "commodo", "consequat", "Duis", "aute", "irure",
"dolor", "in", "reprehendrit", "in", "voluptate", "velit",
"esse", "cillum", "dolore", "eu", "fugiat", "nulla",
"pariatur", "Excepteur", "sint", "accaecat", "cupidatat",
"non", "proident", "sunt", "in", "culpa", "qui", "officia",
"deserunt", "mollit" };
MyApp9() {
setBorder(BorderFactory.createLineBorder(Color.RED, 5));
int j = 0;
JPanel panel0 = new JPanel();
panel0.setBorder(BorderFactory.createTitledBorder("Panel 0"));
panel0.setLayout(new BoxLayout(panel0, BoxLayout.LINE_AXIS));
for (int i = 0; i < 4; i++)
panel0.add(new JLabel(lorem[j++]+" "));
JPanel panel1 = new JPanel();
panel1.setBorder(BorderFactory.createTitledBorder("Panel 1"));
panel1.setLayout(new BoxLayout(panel1, BoxLayout.PAGE_AXIS));
for (int i = 0; i < 14; i++)
panel1.add(new JLabel(lorem[j++]));
JPanel panel2 = new JPanel();
panel2.setBorder(BorderFactory.createTitledBorder("Panel 2"));
panel2.setLayout(new BoxLayout(panel2, BoxLayout.PAGE_AXIS));
for (int i = 0; i < 15; i++)
panel2.add(new JLabel(lorem[j++]));
JPanel panel3 = new JPanel();
panel3.setBorder(BorderFactory.createTitledBorder("Panel 3"));
panel3.setLayout(new BoxLayout(panel3, BoxLayout.PAGE_AXIS));
for (int i = 0; i < 2; i++)
panel3.add(new JLabel(lorem[j++]));
JPanel panel4 = new JPanel();
panel4.setBorder(BorderFactory.createTitledBorder("Panel 4"));
panel4.setLayout(new BoxLayout(panel4, BoxLayout.PAGE_AXIS));
for (int i = 0; i < 8; i++)
panel4.add(new JLabel(lorem[j++]));
JPanel panel5 = new JPanel();
panel5.setBorder(BorderFactory.createTitledBorder("Panel 5"));
panel5.setLayout(new BoxLayout(panel5, BoxLayout.PAGE_AXIS));
for (int i = 0; i < 16; i++)
panel5.add(new JLabel(lorem[j++]));
JPanel panel6 = new JPanel();
panel6.setBorder(BorderFactory.createTitledBorder("Panel 6"));
panel6.setLayout(new BoxLayout(panel6, BoxLayout.PAGE_AXIS));
for (int i = 0; i < 2; i++)
panel6.add(new JLabel(lorem[j++]));
setLayout(new GridBagLayout());
add(panel0, new GBC(0, 0, GBC.REMAINDER, 1));
add(panel1, new GBC(0, 1, 1, GBC.REMAINDER));
add(panel2, new GBC(1, 1, 1, GBC.REMAINDER));
add(panel3, new GBC(2, 1, 1, 1));
add(panel4, new GBC(2, 2, 1, GBC.REMAINDER));
add(panel5, new GBC(3, 1, 1, GBC.REMAINDER));
//add(panel5, new GBC(3, 1, 1, GBC.RELATIVE));
//add(panel6, new GBC(3, 3, 1, 1));
} // constructor
class GBC extends GridBagConstraints {
GBC(int x, int y, int width, int height) {
super(x, y, width, height, 0.0, 0.0,
GridBagConstraints.FIRST_LINE_START,
GridBagConstraints.NONE, new Insets(0, 0, 0, 0),
0, 0);
}
}
private static void createAndShowGUI() {
try {
UIManager.setLookAndFeel(
UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
System.out.println("Unable to set L&F");
}
JFrame.setDefaultLookAndFeelDecorated(true);
JFrame frame = new JFrame("MyApp9");
frame.setContentPane(new MyApp9());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
A. Bolmarcich - 28 Jun 2006 20:46 GMT
> In the GridBagLayout example that follows, all the panels nest nicely
> within the frame with no spare space.
[quoted text clipped - 11 lines]
> Now there is a large blank area at the bottom of the frame. Can anyone
> tell me why?
[example program snipped]
The blank area at the bottom of the frame is there due to the details
of how GridBagLayout determines the preferred height of each row.
GridBagLayout loops over the components in the order that they are in
the container and checks if the preferred height of the component fits
in the preferred row heights determined by the previous iterations of
the loop. If it does not, GridBagLayout increases the preferred
heights of the rows that the component is in.
That approach produces generally expected row heights as long as each
iteration of the loop increases the height of at most one row. That
approach can produce unexpected row heights when an iteration of the
loop distributes increases in height over multiple rows, especially
when the weighty constraint of all the rows is 0.
With your example, the blank area will not be there if you add the
components in the order panel0, panel3, panel6, panel5, panel4, panel1,
panel2. With this order
height of row 0 = height of panel0
height of row 1 = height of panel3
height of row 4 = height of panel6
height of row 2 = height of panel5 - height of row 1
height of row 3 = height of panel4 - height of row 2
Ian Wilson - 29 Jun 2006 11:54 GMT
>>In the GridBagLayout example that follows, all the panels nest nicely
>>within the frame with no spare space.
[quoted text clipped - 38 lines]
> height of row 2 = height of panel5 - height of row 1
> height of row 3 = height of panel4 - height of row 2
Thanks, I tried that and it works. I struggled a bit to understand how
you arrived at that ordering, hence ....
Rule of thumb 1:
If the layout produces excess row height (empty space at bottom of
container), order the add()s by GridBagConstraint.height,
GridBagConstraint.gridy ascending.
Spurred by the provided solution, I did some more experimentation and
was also able to obtain the desired compact layout whilst keeping my
'natural' ordering. I replaced my use of GridBagConstraint.RELATIVE and
GridBagContraint.REMAINDER with actual heights (e.g. 2 or 3) and I set
the height of panel4 to 1, since it didn't actually need to flow into
lower rows.
Rule of thumb 2:
If the layout produces excess space in the container and you have a
component that has empty space beyond it, but which does not need to use
that empty space, don't set that component's GridBagConstraint.width or
height to more than it needs.
I suspect this rule is less likely to succeed if some of the components
can grow when the container is resized.
A. Bolmarcich - 29 Jun 2006 15:43 GMT
> Thanks, I tried that and it works. I struggled a bit to understand how
> you arrived at that ordering, hence ....
The key part of the ordering in your example is to have panel5 in the
container before panel4. What GridBagLayout actually does in more
complicated than I want to try to explain here. Also, I incorrectly
described the height of panel6 affecting the height of row 4; it
affects the height of row 3.
> Rule of thumb 1:
> If the layout produces excess row height (empty space at bottom of
> container), order the add()s by GridBagConstraint.height,
> GridBagConstraint.gridy ascending.
Something similar is true about column widths.
> Spurred by the provided solution, I did some more experimentation and
> was also able to obtain the desired compact layout whilst keeping my
> 'natural' ordering. I replaced my use of GridBagConstraint.RELATIVE and
> GridBagContraint.REMAINDER with actual heights (e.g. 2 or 3) and I set
> the height of panel4 to 1, since it didn't actually need to flow into
> lower rows.
With the "natural" ordering and panel4 having a gridheight of 1, the
height of panel4 affects the height of row 2, the only row it is in.
When panel4 has a gridheight of 2, its height affects the height of row
3, the last row that it occupies, which causes row 3 to have a height
greater than that of panel6.
> Rule of thumb 2:
> If the layout produces excess space in the container and you have a
[quoted text clipped - 4 lines]
> I suspect this rule is less likely to succeed if some of the components
> can grow when the container is resized.
Actually, if the weights of the columns (or rows) is not zero,
GridBagLayout is more likely to produce expected column widths (or row
heights). However, the way that GridBagLayout determines the column and
row weights from the weightx and weighty value of the components, may not
produce the expected results.