JDK-4222758 : GridBagLayout Ordering Bug
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version: 1.2.0,1.2.2,1.3.0,5.0,6
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • OS:
    generic,windows_98,windows_nt,windows_2000,windows_xp generic,windows_98,windows_nt,windows_2000,windows_xp
  • CPU: generic,x86
  • Submitted: 1999-03-22
  • Updated: 2007-07-26
Related Reports
Duplicate :  
Description
Name: dbT83986			Date: 03/22/99


This problem occurs under JDK v1.2 as well as v1.1.7B and
v1.2.1EA.  I'm calling this a "GridBagLayout Ordering Bug" because
the bug occurs depending on the order in which components are added
to a GridBagLayout-managed container.

I've attached a short sample program that illustrates the
buggy behavior.  The attached program is Swing-based.  When I
converted it to use AWT-equivalent components, I saw the exact
same buggy behavior so the bug is definitely not Swing related.

My understanding is that the GridBagLayout does *not* take into
consideration the order in which components are added to a
container it's managing: When a component is added to a container
managed by GridBagLayout, the layout of the container is affected
by the GridBagConstraints object for each component and by the
component itself, *not* by the order in which the components are
added to the container.

I'm seeing a situation where the order in which a component is
added to a GridBagLayout container is significant.  If you run
the attached program, you'll see what I mean.  In the program, I
draw gridlines over the container to show the boundaries of the
GridBagLayout cells.  I also print the widths and heights of the
columns and rows.

Run the attached program.  There are three JLabels on the
JPanel.  The second JLabel is at row 0, column 1 and spans two
columns.  For some reason, GridBagLayout is setting the width of
column 2 to the preferred width of the JLabel.  The result is
that column 2 is much wider than it needs to be (since the JLabel
actually starts in column 1).

Now, switch the order in which the second and third JLabels are
added to the container.  When switching the order be sure to also
switch the corresponding assignments to the GridBagConstraints
object.  If you run the program again you'll see that this time
the third column (column 2) has the correct width.

I briefly checked the "Bug Parade" and did not find any mention
of this bug.  I assume this is a new bug.


Regards.


import javax.swing.*;
import java.awt.*;
import java.awt.event.*;


public class GBLBug {
   public static void main(String[] args) {
      JFrame f = new JFrame("GBL Bug");

      f.getContentPane().add(new UIPane(),
                             BorderLayout.CENTER);

      f.setBounds(50, 50, 550, 100);
      f.setVisible(true);

      f.addWindowListener(new WindowAdapter () {
         public void windowClosing(WindowEvent e) {
            e.getWindow().dispose();
            System.exit(0);
         }
      });
   }
}







class UIPane extends JPanel {
   GridBagLayout gbl = new GridBagLayout();
   JLabel badLabel = new JLabel("----- PROBLEM LABEL PROBLEM LABEL -----");

   public UIPane() {
      GridBagConstraints gbc = new GridBagConstraints();
      setLayout(gbl);

      /**********
      Add the the first JLabel.
      -----------------------------------------------
      grid(x/y)     = (0,0)      grid(width/height) = (1,1)
      weight(x/y)   = (0.0,0.0)  anchor             = WEST
      fill          = NONE       insets             = (0,0,0,0)
      ipad(x,y)     = (0,0)
      **********/
      gbc.gridx     = gbc.gridy      = 0;
      gbc.gridwidth = gbc.gridheight = 1;
      gbc.weightx   = gbc.weighty    = 0.0F;
      gbc.anchor    = GridBagConstraints.WEST;
      gbc.fill      = GridBagConstraints.NONE;
      gbc.insets    = new Insets(0, 0, 0, 0);
      gbc.ipadx     = gbc.ipady = 0;
      add(new JLabel("-- Simple 1x1 JLabel --"), gbc);



      /*!!!!!!!!!!!!!!!!!!!
      When this JLabel is added to a GridBagLayout container
      as the second component, the width of the third column
      (i.e., column 2) is set equal to the preferred width of
      this component, even though this component actually
      starts in the second column (i.e., column 1).  The result
      is that the third column is far wider than it needs to be.
      
      If you move this block of code *below* the next block,
      so that this JLabel is the last component added to the
      container, the third column's width will be sized correctly.
      !!!!!!!!!!!!!!!!!!!*/
      /**********
      Add another JLabel that spans two columns.
      -----------------------------------------------
      grid(x/y)     = (1,0)      grid(width/height) = (2,1)
      weight(x/y)   = (0.0,0.0)  anchor             = WEST
      fill          = NONE       insets             = (0,0,0,0)
      ipad(x,y)     = (0,0)
      **********/
      gbc.gridx      = 1;
      gbc.gridy      = 0;
      gbc.gridwidth  = 2;
      gbc.gridheight = 1;
      add(badLabel, gbc);


      /**********
      Add a JLabel that spans two columns.
      -----------------------------------------------
      grid(x/y)     = (0,1)      grid(width/height) = (2,1)
      weight(x/y)   = (0.0,0.0)  anchor             = WEST
      fill          = NONE       insets             = (0,0,0,0)
      ipad(x,y)     = (0,0)
      **********/
      gbc.gridx      = 0;
      gbc.gridy      = 1;
      gbc.gridwidth  = 2;
      gbc.gridheight = 1;
      add(new JLabel("-- A rather long JLabel that spans two columns --"), gbc);
   }






   public void paint(Graphics g) {
      super.paint(g);
      int[][] grid = gbl.getLayoutDimensions();

      drawGridLines(gbl.getLayoutOrigin(), grid, g);

      System.out.println("The problem label's preferred size is:\n    " +
                         badLabel.getPreferredSize() + '\n');
   }




   private void drawGridLines(Point startPoint, int[][] grid, Graphics g) {
      int   start     = startPoint.x,
      end       = -1,
      increment = startPoint.y - 1;

      // In calculating the ending x position, we must sum all
      // the column widths.
      for(int i = 0; i < grid[0].length; ++i)
         end += grid[0][i];

      end += start;
      g.setColor(Color.red);

      System.out.println("\n\n\nROW and COLUMN SIZES");
      // Draw all the grid rows from left to right, top to bottom.
      for(int i = 0; i < grid[1].length; ++i) {
         ++increment;
         g.drawLine(start, increment, end, increment);

         increment += grid[1][i] - 1;
         g.drawLine(start, increment, end, increment);
         System.out.println("Row " + i + " width  = " + grid[1][i]);
      }

      start     = startPoint.y;
      end       = increment;
      increment = startPoint.x - 1;

      // Draw all the grid columns from top to bottom, left to right.
      for(int i = 0; i < grid[0].length; ++i) {
         ++increment;
         g.drawLine(increment, start, increment, end);

         increment += grid[0][i] - 1;
         g.drawLine(increment, start, increment, end);
         System.out.println("Col " + i + " height = " + grid[0][i]);
      }
   }
}
(Review ID: 55906)
======================================================================

Name: vi73552			Date: 06/03/99


This code demonstrate the use of the GridBagLayout.

The layout use sometimes more space, then it really needed.
The code will demonstrate it.

// start example
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class Test2 {
      public static void main(String[] args) {
            JFrame f = new JFrame("Test GridBagLayout");

            f.getContentPane().add(new TPanel(),BorderLayout.CENTER);

            f.setBounds(50, 50, 500, 150);
            f.setVisible(true);

            f.addWindowListener(new WindowAdapter () {
                  public void windowClosing(WindowEvent e) {
                        e.getWindow().dispose();
                        System.exit(0);
                  }
            });
      }
}

class TPanel extends JPanel {
      public TPanel() {
            JLabel label;
            GridBagLayout gbl = new GridBagLayout();
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.anchor = GridBagConstraints.WEST;
            setLayout(gbl);

            gbc.gridheight = 1;

            gbc.gridy = 0;
            /**********
             Add the the first JLabel.
             **********/
            gbc.gridx = 0;
            gbc.gridwidth = 10;
            add(new JLabel("aaaaaa"), gbc);
            /**********
             Add another JLabel
             **********/
            gbc.gridx = 10;
            gbc.gridwidth = 20;
            add(new JLabel("bbbbbbbbbbbbbb"), gbc);
            /**********
             Add another JLabel
             **********/
            gbc.gridx = 30;
            gbc.gridwidth = 14;
            add(new JLabel("cccccccccc"), gbc);

            gbc.gridy = 1;
            /**********
             Add the the first JLabel.
             **********/
            gbc.gridx = 0;
            gbc.gridwidth = 14;
            add(new JLabel("dddddddddddd"), gbc);
            /**********
             Add another JLabel
             **********/
            gbc.gridx = 14;
            gbc.gridwidth = 10;
            add(new JLabel("eeeeee"), gbc);
            /**********
             Add another JLabel
             **********/
            gbc.gridx = 24;
            gbc.gridwidth = 5;
            add(new JLabel("fffffff"), gbc);
            /**********
             Add another JLabel
             **********/
            gbc.gridx = 29;
            gbc.gridwidth = 10;
            add(new JLabel("ggggggg"), gbc);
            /**********
             Add another JLabel
             **********/
            gbc.gridx = 39;
            gbc.gridwidth = 5;
            add(new JLabel("hhhhhh"), gbc);

            gbc.gridy = 2;
            /**********
             Add the the first JLabel.
             **********/
            gbc.gridx = 0;
            gbc.gridwidth = 10;
            add(new JLabel("Count 1111 :"), gbc);
            /**********
             Add another JLabel
             **********/
            gbc.gridx = 10;
            gbc.gridwidth = 5;
            add(new JLabel("num1"), gbc);
            /**********
             Add another JLabel
             **********/
            gbc.gridx = 15;
            gbc.gridwidth = 10;
            add(new JLabel("Count 2222 :"), gbc);
            /**********
             Add another JLabel
             **********/
            gbc.gridx = 25;
            gbc.gridwidth = 5;
            add(new JLabel("num2"), gbc);
      }
}
// end example
Between some labels is more space then really needed.

The problem is, the order of checking the components in the 
GridBagLayout is important.
In the current implementation of java.awt.GridBagLayout in
method GetLayoutInfo (..) at Pass #3 the components are ascend
ordered by gridx/gridy (there tempX/tempY) to build the array
of gridsize.
If to less space for a component exists, the size of the last-1
grid of the component is increased.
Because of this, the components should be ordered ascend by
(gridx+gridwidth)/(gridy+gridheight).
Then the components will arranged with their minimum requiered space.
The work around describe the change in GridBagLayout.

The components will be better arrange with the new GridBagLayout
(less size), also the frame example in Bug Id 4222758 looks good.

The problem occurs under JDK 1.1.8 and JDK 1.2.2.

Related width Bug Id 4222758
(Review ID: 83866)
======================================================================

Comments
SUGGESTED FIX http://sa.sfbay.sun.com/projects/awt_data/dolphin/4222758.0
17-08-2006

EVALUATION Another layouting order eliminates the problem. We should invent a metric to check if one component is "more important" then second one. We may use following parameters to accomplish that: -pixels per grid cell owned by component -gridx & gridy of component -number of grid cells owned by component
17-08-2006

EVALUATION Contribution-Forum:https://jdk-collaboration.dev.java.net/servlets/ProjectForumMessageView?messageID=11781&forumID=1463
03-03-2006

EVALUATION Name: osR10079 Date: 04/08/2004 The problem is still reproducible with tiger b45. ###@###.### 2004-04-09 ======================================================================
09-04-2004