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

2

11

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);
Along answered 21/8, 2012 at 3:21 Comment(1)
not solving your problem, but couldn't be repeated often enough: don't use setXXSize, ever - https://mcmap.net/q/73928/-should-i-avoid-the-use-of-set-preferred-maximum-minimum-size-methods-in-java-swingShig
G
4

Maybe I have to set the minimum size of the JPanel that contains the buttons?

AFAIR GBL was notorious for ignoring sizing hints. No, a correction on that. To get sensible resizing of components within GBL, use the GridBagConstraints with appropriate values. Beware though, the behavior of the layout to not display any component that would be forced to less than its minimum size.

I would pack() the frame then set the minimum size on the frame. Here is how it might look, changing the last line to..

frame.pack();
frame.setVisible(true);
frame.setMinimumSize(frame.getSize());

Given the layout though, I would tend to put btn1 into the PAGE_START of the BorderLayout of a panel that is then added to the LINE_START of another BL. btn2 would go in the CENTER of the outer BL.

Gujranwala answered 21/8, 2012 at 3:36 Comment(0)
I
8

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.

Inflexion answered 30/4, 2013 at 11:23 Comment(0)
G
4

Maybe I have to set the minimum size of the JPanel that contains the buttons?

AFAIR GBL was notorious for ignoring sizing hints. No, a correction on that. To get sensible resizing of components within GBL, use the GridBagConstraints with appropriate values. Beware though, the behavior of the layout to not display any component that would be forced to less than its minimum size.

I would pack() the frame then set the minimum size on the frame. Here is how it might look, changing the last line to..

frame.pack();
frame.setVisible(true);
frame.setMinimumSize(frame.getSize());

Given the layout though, I would tend to put btn1 into the PAGE_START of the BorderLayout of a panel that is then added to the LINE_START of another BL. btn2 would go in the CENTER of the outer BL.

Gujranwala answered 21/8, 2012 at 3:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.