Java Solaris Communities Sun Store Join SDN My Profile Why Join?
 
Bug Database
Bug Detail
Quick Lists
Top 25 Bugs
Top 25 RFE's
Recently Closed Bugs
Printable Page Printable Page


Bug Database
Bug ID: 4370316
Votes 6
Synopsis GridLayout does not fill its Container
Category java:classes_awt
Reported Against 1.3
Release Fixed 7(b03)
State 10-Fix Delivered, bug
Priority: 4-Low
Related Bugs 4370317 , 6701090 , 6797161
Submit Date 12-SEP-2000
Description


java version "1.3.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0-C)
Java HotSpot(TM) Client VM (build 1.3.0-C, mixed mode)


GridLayout does not fill its Container correctly.  The layoutContainer
(Container) implementation does not take into account the remainder left over
from dividing the parent container's width/height by the number of columns/rows
to get the dimensions of the cells.  As a result, extra space is left to the
right/below the grid of cells.  The following program demonstrates this bug:

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

public class Test extends JFrame {
  public Test() {
    super("Test");
    addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
	dispose();
	System.exit(0);
      }
    });

    JPanel yellowPanel = new JPanel(new GridLayout(30, 1));
    yellowPanel.setBackground(Color.yellow);
    yellowPanel.setOpaque(true);
    for(int i = 0; i < 30; i++) {
      JLabel redLabel = new JLabel();
      redLabel.setBackground(Color.red);
      redLabel.setOpaque(true);
      yellowPanel.add(redLabel);
    }

    JPanel bluePanel = new JPanel(new GridLayout(1, 30));
    bluePanel.setBackground(Color.blue);
    bluePanel.setOpaque(true);
    for(int i = 0; i < 30; i++) {
      JLabel greenLabel = new JLabel();
      greenLabel.setBackground(Color.green);
      greenLabel.setOpaque(true);
      bluePanel.add(greenLabel);
    }

    Container c = getContentPane();
    c.setLayout(new GridLayout(2, 1));
    
    c.add(yellowPanel);
    c.add(bluePanel);

    setSize(200, 200);
    setVisible(true);
  }

  private class MyGridLayout implements LayoutManager {
    int rowCount;
    int colCount;
    
    public MyGridLayout(int rowCount, int colCount) {
      this.rowCount = rowCount;
      this.colCount = colCount;
    }
    
    public void addLayoutComponent(String name, Component child) {
    }
    
    public void removeLayoutComponent(Component child) {
    }
    
    public Dimension preferredLayoutSize(Container parent) {
      Component[] children = parent.getComponents();
      int length = children.length;
      int prefWidth = 0;
      int prefHeight = 0;
      for(int i = 0; i < length; i++) {
	Dimension prefSize = children[i].getPreferredSize();
	if(prefSize.width > prefWidth) prefWidth = prefSize.width;
	if(prefSize.height > prefHeight) prefHeight = prefSize.height;
      }
      return new Dimension(colCount * prefWidth, rowCount * prefHeight);
    }
   
    public Dimension minimumLayoutSize(Container parent) {
      Component[] children = parent.getComponents();
      int length = children.length;
      int minWidth = 0;
      int minHeight = 0;
      for(int i = 0; i < length; i++) {
	Dimension minSize = children[i].getMinimumSize();
	if(minSize.width > minWidth) minWidth = minSize.width;
	if(minSize.height > minHeight) minHeight = minSize.height;
      }
      return new Dimension(colCount * minWidth, rowCount * minHeight);
    }

    public void layoutContainer(Container parent) {
      int width = parent.getWidth() / colCount + 1;
      int widthRemainder = parent.getWidth() % colCount;
      int height = parent.getHeight() / rowCount + 1;
      int heightRemainder = parent.getHeight() % rowCount;
      Component[] children = parent.getComponents();
      int i = 0;
      int y = 0;
      for(int row = 0; row < heightRemainder; row++) {
	int x = 0;
	for(int col = 0; col < widthRemainder; col++) {
	  children[i++].setBounds(x, y, width, height);
	  x += width;
	}
	width--;
	for(int col = widthRemainder; col < colCount; col++) {
	  children[i++].setBounds(x, y, width, height);
	  x += width;
	}
	y += height;
	width++;
      }
      height--;
      for(int row = heightRemainder; row < rowCount; row++) {
	int x = 0;
	for(int col = 0; col < widthRemainder; col++) {
	  children[i++].setBounds(x, y, width, height);
	  x += width;
	}
	width--;
	for(int col = widthRemainder; col < colCount; col++) {
	  children[i++].setBounds(x, y, width, height);
	  x += width;
	}
	y += height;
	width++;
      }
    }
  }

  public static void main(String[] args) {
    new Test();
  }
}

If you resize the frame, you can see the yellow/blue backgrounds of the
GridLayout containers show through.  The program includes my own implementation
of GridLayout that takes care of the problem.  Replace the GridLayout
instantiations with MyGridLayout ones, and you can't see the yellow or blue
anymore.  Problem solved.

Of course now the cells aren't all eqaully sized (some are wider/higher than
others by 1 pixel), but I'm sure anyone who uses GridLayout would rather have
this behavior than the current (undocumented) behavior.
(Review ID: 108090) 
======================================================================
Posted Date : 2006-03-15 09:43:07.0
Work Around


Use MyGridLayout instead of GridLayout.
======================================================================
Evaluation
Contribution-Forum:https://jdk-collaboration.dev.java.net/servlets/ProjectForumMessageView?messageID=11902&forumID=1463
Posted Date : 2006-03-10 05:38:22.0

As there is no good way to distribute remaining space between components equally we may try to position components in the center of container without addtional space distibution.
To accomplish that we have to calculate remaining space (by both axes) and start layouting components from that value(s) divided by 2.
Following chunk of code is self-explanaroty:
        int totalGapsWidth = (ncols - 1) * hgap;
        int widthWOInsets = parent.width - (insets.left + insets.right);
        int widthOnComponent = (widthWOInsets - totalGapsWidth)/ncols;
        int extraWidthAvailable = (widthWOInsets - (widthOnComponent * ncols + totalGapsWidth))/2;
Posted Date : 2006-08-17 08:02:26.0

When obtaining widthOnComponent we do implicit cast from double to int i.e. ignore fractional part. So extraWidthAvailable is not equal to zero because widthOnComponent holds trancated value.
The other way would to calculate fractional part (widthOnComponentDouble) and multiply with ncols to get extra available space. But this approach supposes explicit cast in several places and may lead to precision loss.
So (ncols * fractional reminder) would be the extraWidthAvailable for that approach.
Posted Date : 2006-09-21 08:41:47.0
Comments
  
  Include a link with my name & email   


PLEASE NOTE: JDK6 is formerly known as Project Mustang