Search code examples
javaswingsizelayout-managergridbaglayout

Make GridBagLayout JPanel size to contents, not container?


I have a GridBagLayout JPanel contained within a BorderLayout JPanel. I want the GridBagLayout to size itself to its internal grid. Instead, it sizes itself to the BorderLayout, adding whitespace to the sides of the internal grid (all weights in the GridBagLayout are 0).

The idea is that I want the BorderLayout to supply the whitespace (with glue). Instead, the GridBagLayout is supplying the whitespace; you can see that by looking at the TitleBorder I added.

The reason for this is that when I send the GridBagLayout to my printer, I don't want all that whitespace included.

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

public class GBLDemo {
    public static void main (String[] args) {
        JFrame jframe = new JFrame("GridBagLayout Demo");
        jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        Container contentPane = new JPanel(new BorderLayout());
        jframe.setContentPane(contentPane);

        GridBagConstraints gbc = new GridBagConstraints();
        JPanel gb = new JPanel(new GridBagLayout());
        contentPane.add(gb);

        gbc.gridx = gbc.gridy = 0;
        gb.add(new JLabel("Look "), gbc);

        gbc.gridx = 1;
        gb.add(new JLabel("at"), gbc);         

        gbc.gridx = 0;
        gbc.gridy = 1;
        gb.add(new JLabel("the "), gbc);

        gbc.gridx = 1;
        gb.add(new JLabel("border"), gbc);

        gb.setBorder(BorderFactory.createTitledBorder("Border"));

        jframe.pack();
        jframe.setVisible(true);
        jframe.setSize(640, 480);
    } // main(args)
} // GBLDemo

Here's an ASCII mockup of what I want:

+-------------------------------------------+
|                                           |
|                                           |
|           +Border-----+                   |
|           |Look  at   |                   |
|           | the border|                   |
|           +-----------+                   |
|                                           |
|                                           |
+-------------------------------------------+

Here's the display produced by the code above:

enter image description here


Solution

  • A good trick for center a component at its preferred size (e.g. the contentPane in the code in the question) is to add it as a single component to a container with a grid bag layout, without specifying a constraint.

    Here is the code from above, adapted to do exactly that.

    import java.awt.*;
    import javax.swing.*;
    import javax.swing.border.EmptyBorder;
    
    public class GBLDemo {
    
        private JComponent ui = null;
    
        GBLDemo() {
            initUI();
        }
    
        private Container getContentPanel() {
            Container contentPane = new JPanel(new BorderLayout());
    
            GridBagConstraints gbc = new GridBagConstraints();
            JPanel gb = new JPanel(new GridBagLayout());
            contentPane.add(gb);
    
            gbc.gridx = gbc.gridy = 0;
            gb.add(new JLabel("Look "), gbc);
    
            gbc.gridx = 1;
            gb.add(new JLabel("at"), gbc);         
    
            gbc.gridx = 0;
            gbc.gridy = 1;
            gb.add(new JLabel("the "), gbc);
    
            gbc.gridx = 1;
            gb.add(new JLabel("border"), gbc);
    
            gb.setBorder(BorderFactory.createTitledBorder("Border"));
            return contentPane;
        }
    
        public void initUI() {
            if (ui!=null) return;
    
            // A single object added to a grid bag layout with no constraint, 
            // will be centered within the available space.
            ui = new JPanel(new GridBagLayout()); 
            ui.setBorder(new EmptyBorder(4,4,4,4));
    
            ui.add(getContentPanel());
        }
    
        public JComponent getUI() {
            return ui;
        }
    
        public static void main(String[] args) {
            Runnable r = new Runnable() {
                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (Exception useDefault) {
                    }
                    GBLDemo o = new GBLDemo();
    
                    JFrame f = new JFrame(o.getClass().getSimpleName());
                    f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                    f.setLocationByPlatform(true);
    
                    f.setContentPane(o.getUI());
                    f.pack();
                    f.setMinimumSize(f.getSize());
    
                    f.setVisible(true);
                }
            };
            SwingUtilities.invokeLater(r);
        }
    }