How to get GridBagLayout to respect minimum size of a button or panel?

user550738 picture user550738 · Aug 21, 2012 · Viewed 13.6k times · Source

In the following GridBagLayout code, I'm expecting the specified minimum size of JButton btn2 to be respected when the JFrame is resized to be made smaller. But when I make the JFrame smaller, the btn2 gets smaller than its minimum size and then vanishes.

Can someone point me in the right direction of what I'm doing wrong? Maybe I have to set the minimum size of the JPanel that contains the buttons?

Any help is appreciated, thanks!

    JFrame frame = new JFrame();
    frame.setSize(400,300);
    frame.setLocationRelativeTo(null);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    JPanel panel = new JPanel();
    panel.setMinimumSize(new Dimension(400,300));
    panel.setBackground(Color.RED);

    panel.setLayout(new GridBagLayout());
    GridBagConstraints gbc = null;

    JButton btn1 = new JButton("btn1");
    btn1.setPreferredSize(new Dimension(150,50));
    btn1.setMinimumSize(new Dimension(150,50));
    gbc = new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, 
            GridBagConstraints.NORTHWEST, GridBagConstraints.NONE,
            new Insets(0,0,0,0), 0, 0);
    panel.add(btn1, gbc);

    JButton btn2 = new JButton("btn2");
    btn2.setPreferredSize(new Dimension(150,150));
    btn2.setMinimumSize(new Dimension(150,150));
    gbc = new GridBagConstraints(1, 0, 1, 1, 1.0, 1.0, 
            GridBagConstraints.NORTHWEST, GridBagConstraints.BOTH,
            new Insets(0,0,100,100), 0, 0);
    panel.add(btn2, gbc);

    frame.getContentPane().add(panel);
    frame.setVisible(true);

Answer

Timmos picture Timmos · Apr 30, 2013

In addition to Andrew Thompson's answer:

  • The GBL DOES NOT respect the minimum size set on a component if the component's preferred size can and will be respected.
  • The GBL DOES respect the minimum size set on a component when the component's preferred size cannot be respected, that is: the component prefers to be of size (w,h) but the GBL sees this is impossible due to lack of space, and therefore it falls back on the advertised minimum size of the component.

It is therefore very much possible to make your component suddenly become larger than it was before when you downsize the containing frame. You only have to set a minimum size on it that is larger than the preferred size. So you are making the frame smaller, and suddenly your component becomes larger. That is... weird but possible :) All hail GBL.

Here is an example of a panel that implements this behavior (GBC is an easier class to use than the original GridBagConstraints):

private static JPanel getPanel() {

    JPanel panel = new JPanel(new GridBagLayout());

    final JTextField textField = new JTextField("test");
    final String text = "text";
    final JLabel label = new JLabel(text);
    final JButton button = new JButton(new AbstractAction("Enlarge label!") {
        private String actText = text; 
        @Override
        public void actionPerformed(ActionEvent arg0) {
            actText = actText + text;
            label.setText(actText);
        }
    });

    GBC g;

    g = new GBC().locate(0, 0).weight(0.0, 0.0).align(GBC.WEST, GBC.HORIZONTAL, null);
    textField.setMinimumSize(new Dimension(200,20));
    panel.add(textField, g);

    g = new GBC().locate(1, 0).weight(1.0, 0.0);
    panel.add(label, g);

    g = new GBC().locate(0, 1).weight(1.0, 1.0).span(2, 1);
    panel.add(button, g);


    return panel;
}

In general, I would say to not use components that must be fixed in size within a GBL. Wrap it inside other panels with different layout managers.

If you really want to use your fixed-sized component within a GBL, override its getPreferredSize() method and return the size you want. But I prefer to ignore these methods.