javaswinglayout-managergridbaglayout

GridBagLayout 25% 50% 25%


Is this the right way to prevent GridBagLayout cells from being resized relative to their contents?

gbl_panel.columnWidths = new int[] {1000, 4000, 1000};

enter image description here

SSCCE

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;

import javax.swing.AbstractListModel;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.border.EmptyBorder;

public class GridBagLayoutTemplate extends JFrame {

private JPanel contentPane;

public GridBagLayoutTemplate() {
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setBounds(100, 100, 450, 300);
    contentPane = new JPanel();
    contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
    contentPane.setLayout(new BorderLayout(0, 0));
    setContentPane(contentPane);


    JPanel panel = new JPanel();
    contentPane.add(panel);

    GridBagLayout gbl_panel = new GridBagLayout();
    gbl_panel.rowHeights = new int[] {1};
    gbl_panel.columnWidths = new int[] {1000, 4000, 1000};
    gbl_panel.columnWeights = new double[]{1.0, 4.0, 1.0};
    gbl_panel.rowWeights = new double[]{1.0};
    panel.setLayout(gbl_panel);

    JScrollPane scrollPane = new JScrollPane();
    GridBagConstraints gbc_scrollPane = new GridBagConstraints();
    gbc_scrollPane.insets = new Insets(0, 0, 0, 5);
    gbc_scrollPane.fill = GridBagConstraints.BOTH;
    gbc_scrollPane.gridx = 0;
    gbc_scrollPane.gridy = 0;
    panel.add(scrollPane, gbc_scrollPane);

    JList list = new JList();
    scrollPane.setViewportView(list);
    list.setModel(new AbstractListModel() {
        String[] values = new String[] {"qwe"};
        public int getSize() {
            return values.length;
        }
        public Object getElementAt(int index) {
            return values[index];
        }
    });

    JScrollPane scrollPane_1 = new JScrollPane();
    GridBagConstraints gbc_scrollPane_1 = new GridBagConstraints();
    gbc_scrollPane_1.insets = new Insets(0, 0, 0, 5);
    gbc_scrollPane_1.fill = GridBagConstraints.BOTH;
    gbc_scrollPane_1.gridx = 1;
    gbc_scrollPane_1.gridy = 0;
    panel.add(scrollPane_1, gbc_scrollPane_1);

    JList list_1 = new JList();
    scrollPane_1.setViewportView(list_1);
    list_1.setModel(new AbstractListModel() {
        String[] values = new String[] {"qwe"};
        public int getSize() {
            return values.length;
        }
        public Object getElementAt(int index) {
            return values[index];
        }
    });

    JScrollPane scrollPane_2 = new JScrollPane();
    GridBagConstraints gbc_scrollPane_2 = new GridBagConstraints();
    gbc_scrollPane_2.fill = GridBagConstraints.BOTH;
    gbc_scrollPane_2.gridx = 2;
    gbc_scrollPane_2.gridy = 0;
    panel.add(scrollPane_2, gbc_scrollPane_2);

    JList list_3 = new JList();
    scrollPane_2.setViewportView(list_3);
    list_3.setModel(new AbstractListModel() {
        String[] values = new String[] {"qweqweqweqweqwqweqweqweqweqweqweqweqweqwqweqweqweqweqweqweqweqwqweqweqweqweqweqweqweqweqwqweqweqweqweqweqweqweqweqwqweqweqweqweqwqweqweqweqweqweqweqweqweqwqweqweqweqweqweqweqweqweqwqweqweqweqwe"};
        public int getSize() {
            return values.length;
        }
        public Object getElementAt(int index) {
            return values[index];
        }
    });
}
}

public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
        public void run() {
            try {
                GridBagLayoutTemplate frame = new GridBagLayoutTemplate();
                frame.setVisible(true);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    });
}

Solution

  • Interesting. I've never seen an approach like this before.

    Typically the GridBagLayout is used such that:

    1. Each component is allocated space based on its preferred size
    2. If extra space is available then space is allocated to to each component based on the weightx (weighty) values assigned to each component.

    Therefore only the extra space is allocated in the 25% 50% 25% ratio.

    Your approach seems to ignore the preferred size of components and allocate space in the 25% 50% 25% ratio.

    However, you would first need to make the following change to get the proper ratio:

    //gbl_panel.columnWidths = new int[] {1000, 4000, 1000};
    //gbl_panel.columnWeights = new double[]{1.0, 4.0, 1.0};
    gbl_panel.columnWidths = new int[] {1000, 2000, 1000};
    gbl_panel.columnWeights = new double[]{1.0, 2.0, 1.0};
    

    Below is the simplified code I used to test allocating space to components on a panel that is 400 pixels wide:

    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    
    public class GridBagLayoutRelative extends JPanel
    {
        public GridBagLayoutRelative()
        {
            setPreferredSize( new Dimension(400, 300) );
    
            //  Components will be allocated relative widths of 25%, 50%, 25%
            //  (preferred width will be ignored)
    
            GridBagLayout gbl = new GridBagLayout();
            //gbl.columnWidths = new int[] {25, 50, 25}; // doesn't work
            gbl.columnWidths = new int[] {250, 500, 250}; // larger value in same ratio
            gbl.columnWeights = new double[] {25.0, 50.0, 25.0};
            setLayout(gbl);
    
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.fill = GridBagConstraints.BOTH;
            gbc.weighty = 1.0;
            gbc.gridy = 0;
    
            JPanel red = new JPanel();
            red.setBackground( Color.RED );
            red.setPreferredSize( new Dimension(30, 200) );
            gbc.gridx = 0;
            add(red, gbc);
    
            JPanel green = new JPanel();
            green.setBackground( Color.GREEN );
            green.setPreferredSize( new Dimension(40, 200) );
            gbc.gridx = 1;
            add(green, gbc);
    
            JPanel blue = new JPanel();
            blue.setBackground( Color.BLUE );
            blue.setPreferredSize( new Dimension(50, 200) );
            gbc.gridx = 2;
            add(blue, gbc);
    
            addComponentListener( new ComponentAdapter()
            {
                @Override
                public void componentResized(ComponentEvent e)
                {
                    System.out.println( e.getComponent().getSize() );
    
                    for (Component c: getComponents())
                        System.out.println( "\t" + c.getSize() );
                }
            });
        }
    
        private static void createAndShowGUI()
        {
            JFrame frame = new JFrame("GridBagLayout Relative");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(new GridBagLayoutRelative());
            frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
            frame.pack();
            frame.setLocationByPlatform( true );
            frame.setVisible( true );
        }
    
        public static void main(String[] args) throws Exception
        {
            java.awt.EventQueue.invokeLater( () -> createAndShowGUI() );
        }
    }
    

    And the results are:

    java.awt.Dimension[width=100,height=300]
    java.awt.Dimension[width=200,height=300]
    java.awt.Dimension[width=100,height=300]
    

    So I would say the approach works.

    Note: In case you are interested, in the past I have suggested you can use the Relative Layout which was designed specifically for this type of layout and is easier to use.

    Using the RelativeLayout the above behaviour would be replicated by using:

    RelativeLayout rl = new RelativeLayout(RelativeLayout.X_AXIS);
    rl.setFill(true);
    setLayout( rl );
    
    JPanel red = new JPanel();
    red.setBackground( Color.RED );
    red.setPreferredSize( new Dimension(30, 200) );
    add(red, new Float(25));
    
    JPanel green = new JPanel();
    green.setBackground( Color.GREEN );
    green.setPreferredSize( new Dimension(40, 200) );
    add(green, new Float(50));
    
    JPanel blue = new JPanel();
    blue.setBackground( Color.BLUE );
    blue.setPreferredSize( new Dimension(50, 200) );
    add(blue, new Float(25));