javaswinglayout-managergridbaglayout

Why does this GridBagLayout not appear as planned?


I was trying to achieve the end result required in Setting an arbitrary width in GridBagLayout.

For easy reference, here it is:

This is the current result:

Button number and row is shown in the form 1,1, followed by the number of columns (2) declared for this cell.

As you can see, it starts with buttons 1,1 (3) and below it 1,2 (4) being the same width, while declaring different numbers of columns.

Can anyone determine how to correct the code?

The current code:

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

public class KeyBoardLayout {

    private JComponent ui = null;

    KeyBoardLayout() {
        initUI();
    }

    public void initUI() {
        if (ui!=null) return;

        ui = new JPanel(new GridBagLayout());
        ui.setBorder(new EmptyBorder(4,4,4,4));

        GridBagConstraints gbc = new GridBagConstraints();

        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.gridwidth = 3;
        gbc.fill = GridBagConstraints.HORIZONTAL;
        ui.add(new JButton("1,1 (3)"), gbc);

        gbc.gridx = 3;
        gbc.gridwidth = 2;
        ui.add(new JButton("2,1 (2)"), gbc);

        gbc.gridx = 5;
        ui.add(new JButton("3,1 (2)"), gbc);

        gbc.gridx = 7;
        ui.add(new JButton("4,1 (2)"), gbc);

        gbc.gridx = 9;
        ui.add(new JButton("5,1 (2)"), gbc);

        gbc.gridx = 11;
        ui.add(new JButton("6,1 (2)"), gbc);

        gbc.gridx = 13;
        ui.add(new JButton("7,1 (2)"), gbc);

        gbc.gridx = 15;
        gbc.gridwidth = 3;
        ui.add(new JButton("8,1 (3)"), gbc);

        gbc.gridx = 18;
        gbc.gridwidth = 4;
        ui.add(new JButton("9,1 (4)"), gbc);

        gbc.gridx = 0;
        gbc.gridy = 1;
        ui.add(new JButton("1,2 (4)"), gbc);

        gbc.gridx = 4;
        gbc.gridwidth = 2;
        ui.add(new JButton("2,2 (2)"), gbc);

        gbc.gridx = 6;
        ui.add(new JButton("3,2 (2)"), gbc);

        gbc.gridx = 8;
        ui.add(new JButton("4,2 (2)"), gbc);

        gbc.gridx = 10;
        ui.add(new JButton("5,2 (2)"), gbc);

        gbc.gridx = 12;
        ui.add(new JButton("6,2 (2)"), gbc);

        gbc.gridx = 14;
        ui.add(new JButton("7,2 (2)"), gbc);

        gbc.gridx = 16;
        ui.add(new JButton("8,2 (2)"), gbc);

        gbc.gridx = 18;
        gbc.gridwidth = 4;
        ui.add(new JButton("9,2 (4)"), gbc);

        gbc.gridx = 0;
        gbc.gridy = 2;
        gbc.gridwidth = 5;
        ui.add(new JButton("1,3 (5)"), gbc);

        gbc.gridx = 5;
        gbc.gridwidth = 2;
        ui.add(new JButton("2,3 (2)"), gbc);

        gbc.gridx = 7;
        ui.add(new JButton("3,3 (2)"), gbc);

        gbc.gridx = 9;
        ui.add(new JButton("4,3 (2)"), gbc);

        gbc.gridx = 11;
        ui.add(new JButton("5,3 (2)"), gbc);

        gbc.gridx = 13;
        ui.add(new JButton("6,3 (2)"), gbc);

        gbc.gridx = 15;
        ui.add(new JButton("7,3 (2)"), gbc);

        gbc.gridx = 17;
        ui.add(new JButton("8,3 (2)"), gbc);

        gbc.gridx = 19;
        gbc.gridwidth = 3;
        ui.add(new JButton("9,3 (3)"), gbc);

        gbc.gridx = 0;
        gbc.gridy = 3;
        gbc.gridwidth = 3;
        ui.add(new JButton("1,4 (3)"), gbc);

        gbc.gridx = 3;
        ui.add(new JButton("2,4 (3)"), gbc);

        gbc.gridx = 6;
        gbc.gridwidth = 10;
        ui.add(new JButton("3,4 (10)"), gbc);

        gbc.gridx = 16;
        gbc.gridwidth = 3;
        ui.add(new JButton("4,4 (3)"), gbc);

        gbc.gridx = 19;
        ui.add(new JButton("5,4 (3)"), gbc);
    }

    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) {
                }
                KeyBoardLayout o = new KeyBoardLayout();

                JFrame f = new JFrame("Keyboard Layout");
                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);
    }
}

Solution

  • From the picture each row contains 5 to 9 buttons, which means the GridBagLayout only knows about the width of 9 individual columns.

    Add up the numbers in the (..) which indicate the total gridwidth for each row. The total is 22.

    The GridBagLayout doesn't know how to turn 9 columns into 22 columns. It doesn't know what widths to use for columns without a component in the column. So the layout doesn't know how to handle the gridwidth constraint.

    The solution is to tell the GridBagLayout the intended number of columns in the grid and the minimum width of each column in the grid.

    This can be done by setting values of the GridBagLayout itself:

    //ui = new JPanel(new GridBagLayout());
    int[] columns = new int[22];
    Arrays.fill(columns, 30);
    GridBagLayout gbl = new GridBagLayout();
    gbl.columnWidths = columns;
    ui = new JPanel(gbl);
    

    The size of the array defines the number of columns.

    The value assigned to each entry in the array is the "minimum width" of the column (it can be different for each column).

    Now the GridBagLayout knows how to calculate a width for each column and using gridwidth as a constraint for each component will work as expected.

    Updated code is as follows:

    import java.awt.*;
    import java.util.Arrays;
    import javax.swing.*;
    import javax.swing.border.EmptyBorder;
    
    public class KeyBoardLayout {
    
        private JComponent ui = null;
    
        KeyBoardLayout() {
            initUI();
        }
    
        public void initUI() {
            if (ui!=null) return;
    
    
            //ui = new JPanel(new GridBagLayout());
            int[] columns = new int[22];
            Arrays.fill(columns, 30);
            GridBagLayout gbl = new GridBagLayout();
            gbl.columnWidths = columns;
            ui = new JPanel(gbl);
    
            ui.setBorder(new EmptyBorder(4,4,4,4));
    
            GridBagConstraints gbc = new GridBagConstraints();
    
            gbc.gridx = 0;
            gbc.gridy = 0;
            gbc.gridwidth = 3;
            gbc.fill = GridBagConstraints.HORIZONTAL;
            ui.add(new JButton("1,1 (3)"), gbc);
    
            gbc.gridx = 3;
            gbc.gridwidth = 2;
            ui.add(new JButton("2,1 (2)"), gbc);
    
            gbc.gridx = 5;
            ui.add(new JButton("3,1 (2)"), gbc);
    
            gbc.gridx = 7;
            ui.add(new JButton("4,1 (2)"), gbc);
    
            gbc.gridx = 9;
            ui.add(new JButton("5,1 (2)"), gbc);
    
            gbc.gridx = 11;
            ui.add(new JButton("6,1 (2)"), gbc);
    
            gbc.gridx = 13;
            ui.add(new JButton("7,1 (2)"), gbc);
    
            gbc.gridx = 15;
            gbc.gridwidth = 3;
            ui.add(new JButton("8,1 (3)"), gbc);
    
            gbc.gridx = 18;
            gbc.gridwidth = 4;
            ui.add(new JButton("9,1 (4)"), gbc);
    
            gbc.gridx = 0;
            gbc.gridy = 1;
            ui.add(new JButton("1,2 (4)"), gbc);
    
            gbc.gridx = 4;
            gbc.gridwidth = 2;
            ui.add(new JButton("2,2 (2)"), gbc);
    
            gbc.gridx = 6;
            ui.add(new JButton("3,2 (2)"), gbc);
    
            gbc.gridx = 8;
            ui.add(new JButton("4,2 (2)"), gbc);
    
            gbc.gridx = 10;
            ui.add(new JButton("5,2 (2)"), gbc);
    
            gbc.gridx = 12;
            ui.add(new JButton("6,2 (2)"), gbc);
    
            gbc.gridx = 14;
            ui.add(new JButton("7,2 (2)"), gbc);
    
            gbc.gridx = 16;
            ui.add(new JButton("8,2 (2)"), gbc);
    
            gbc.gridx = 18;
            gbc.gridwidth = 4;
            ui.add(new JButton("9,2 (4)"), gbc);
    
            gbc.gridx = 0;
            gbc.gridy = 2;
            gbc.gridwidth = 5;
            ui.add(new JButton("1,3 (5)"), gbc);
    
            gbc.gridx = 5;
            gbc.gridwidth = 2;
            ui.add(new JButton("2,3 (2)"), gbc);
    
            gbc.gridx = 7;
            ui.add(new JButton("3,3 (2)"), gbc);
    
            gbc.gridx = 9;
            ui.add(new JButton("4,3 (2)"), gbc);
    
            gbc.gridx = 11;
            ui.add(new JButton("5,3 (2)"), gbc);
    
            gbc.gridx = 13;
            ui.add(new JButton("6,3 (2)"), gbc);
    
            gbc.gridx = 15;
            ui.add(new JButton("7,3 (2)"), gbc);
    
            gbc.gridx = 17;
            ui.add(new JButton("8,3 (2)"), gbc);
    
            gbc.gridx = 19;
            gbc.gridwidth = 3;
            ui.add(new JButton("9,3 (3)"), gbc);
    
            gbc.gridx = 0;
            gbc.gridy = 3;
            gbc.gridwidth = 3;
            ui.add(new JButton("1,4 (3)"), gbc);
    
            gbc.gridx = 3;
            ui.add(new JButton("2,4 (3)"), gbc);
    
            gbc.gridx = 6;
            gbc.gridwidth = 10;
            ui.add(new JButton("3,4 (10)"), gbc);
    
            gbc.gridx = 16;
            gbc.gridwidth = 3;
            ui.add(new JButton("4,4 (3)"), gbc);
    
            gbc.gridx = 19;
            ui.add(new JButton("5,4 (3)"), gbc);
        }
    
        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) {
                    }
                    KeyBoardLayout o = new KeyBoardLayout();
    
                    JFrame f = new JFrame("Keyboard Layout");
                    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);
        }
    }
    

    Which would give the following layout:

    https://i.sstatic.net/GiqAz.png

    This approach can be used for rows as well.

    This means the GridBagLayout provides the ability to create a grid and only fill a few cells of the grid with components.