Resizing fails in Java Frames on Macintosh OS X using GridBagLayout

(Apple Problem ID# 2809581)

    When a Java Frame is resized, the information about the new size can typically be intercepted in the setBounds method.  This information can be used to make adjustments to the display, for example decreasing the number of components displayed.  This is not working properly in MRJ 3.1 for Macintosh OS X using GridBagLayout.  It works in all other environments tested: MRJ 2.2.5 for Macintosh OS 9, and Java Virtual Machine for Windows from Microsoft, Sun and Netscape.
    The applet below, which appears as a yellow bar, illustrates this problem.  It pops up a Frame that contains initially 4 blue bars.  As the height of the Frame is made smaller, the number of bars should be reduced so all bars fit on the Frame, using information sensed in the setBounds method of the Panel.  This fails on Macintosh OS 10.1; the user is unable to resize the frame smaller than the space occupied by the initial 4 bars.  There appears to be no opportunity for the setBounds method in the Panel to get the height information and change the number of bars (but note the workaround / solution below).
    Using FlowLayout for the Panel, instead of GridBagLayout, resizing works properly, as illustrated at Resizing using FlowLayout with a working applet and source code.  In that FlowLayout example it is possible to reduce the size of the Frame without limit.
    Using GridBagLayout and leaving extra room around the bars before reducing the number of bars produces different results depending on the amount of extra room left.  As illustrated with a working applet and source code at Resizing Leaving Extra Room, changing the line in setBounds from:
int barsToShow = height/(barHeight + pad + pad);
to:
int barsToShow = height/(barHeight + pad + pad + 10);
results in a situation in which the number of bars can be reduced one at a time until 2 bars are left, after which no further reduction can be made.  The behavior of the applet is different for values other than 10; these results are summarized in a table at Resizing Leaving Extra Room.
    There is no problem making Frames on applets smaller as long as there are no fixed-size Components on the Frame, as illustrated using an applet created for an unrelated bug report
    Using JDK methods such as reshape instead of setBounds does not change the behavior, as shown at Resizing using JDK 1.0 methods.
    This problem is seen in all OS 10.1 / MRJ 3.1 environments:  Applet Launcher, Internet Explorer 5.1.3 and Netscape 6.2 with MRJ Plugin.  On Internet Explorer 5.0 for Macintosh OS 9 there are some minor display problems involving the bottom bar of the Frame.  
    Daniel Bobbert suggested that the limitation on resizing Frames in MRJ 3.1 for OS X could be overcome by overriding getMinimumSize in the Frame.  This works, and is demonstrated with a working applet and source code at Resizing after overriding getMinimumSize in the Frame.  This certainly qualifies as an acceptable workaround.  It may even be a good solution to the problem, though my favorite solution would be to have resizing with GridBagLayout behave like resizing with FlowLayout.

    If you have any insights, workarounds or comments about this test page please contact Mickey Segal.  A listing of  many Macintosh Java bugs with demonstration applets is at this link, including information on how to add any necessary Java plugins.

    The source code is shown below and can be downloaded from this link:

import java.applet.*;
import java.awt.*;
import java.awt.event.*;

public class Resizing extends Applet {

public void init() 
{
    setBackground(Color.yellow);
    PoliteFrame frame = new PoliteFrame("A frame");
    PanelWithBars panelWithBars = new PanelWithBars();
    frame.add(panelWithBars);
    frame.setBounds(300, 100, 400, 550); 
    frame.validate();
    frame.show();
}
} // END OF Class Resizing


class PanelWithBars extends Panel {

int barsShowing, maxBars, barHeight, pad;
Bar[] bar;

PanelWithBars()
{
    setLayout(new GridBagLayout());
    barsShowing = maxBars = 4;
    barHeight = 100;
    pad = 5;
    bar = new Bar[maxBars]; 
    for (int i=0; i<maxBars; i++)
    {
        bar[i] = new Bar(barHeight);
        addBar(i);
    }
}

public void setBounds(int x, int y, int width, int height)
{
    int barsToShow = height/(barHeight + pad + pad);
    if (barsToShow > maxBars) barsToShow = maxBars;
    if (barsToShow < barsShowing) for (int i = barsToShow; i<barsShowing; i++) remove(bar[i]);
    else if (barsToShow > barsShowing) for (int i = barsShowing; i<barsToShow; i++) addBar(i);
    barsShowing = barsToShow;
    super.setBounds(x, y, width, height);
}

void addBar(int index)
{
    constrain(this, bar[index], 0, index, 1, 1, GridBagConstraints.NORTH, pad, pad, pad, pad, GridBagConstraints.NONE, 0, 0);
}

static final void constrain(Container container, Component component, int grid_x, int grid_y, 
    int grid_width, int grid_height, int anchor, int topPad, int leftPad, int bottomPad, 
    int rightPad, int fill, double weightx, double weighty)
{
    GridBagConstraints c = new GridBagConstraints();
    c.gridx = grid_x;
    c.gridy = grid_y;
    c.gridwidth = grid_width;
    c.gridheight = grid_height;
    c.anchor = anchor;
    c.insets.top = topPad;
    c.insets.left = leftPad;
    c.insets.bottom= bottomPad;
    c.insets.right = rightPad;
    c.fill = fill;
    c.weightx = weightx;
    c.weighty = weighty;
    ((GridBagLayout)container.getLayout()).setConstraints(component, c);
    container.add(component);
}
} // END OF Class PanelWithBars


class PoliteFrame extends Frame implements WindowListener
{

PoliteFrame(String s)
{
    super(s);
    addWindowListener(this);
}

public void windowOpened(WindowEvent we){}

public void windowClosed(WindowEvent we){}

public void windowIconified(WindowEvent we){}

public void windowDeiconified(WindowEvent we){}

public void windowActivated(WindowEvent we){}

public void windowDeactivated(WindowEvent we){}

public void windowClosing(WindowEvent we)
{
    if (we.getSource() == this)
    {
        setVisible(false);
        dispose();
    }
}
} // END OF Class PoliteFrame



final class Bar extends Canvas {

int width;
int height;

Bar(int height)
{
    this.height = height;
}

public void addNotify()
{
    super.addNotify();
    repaint();
}

public final void paint(Graphics g)
{
    width = getSize().width;
    g.setColor(Color.blue);
    g.fillRect(0, 0, width, height);


public final Dimension getMinimumSize()
{
    return(new Dimension(10, height));
}

public final Dimension getPreferredSize()
{
    return(new Dimension(300, height));
}
} // END OF Class Bar