Search code examples
javaswinglayout-managergridbaglayout

GridBagLayout - I seem to have less columns than I specified, but why?


I am trying to make my frame setup not look ugly, so I decided to dive into layouts.

GridBagLayout seemed the most versatile, so I am experimenting a little with it, in order to understand it. My problem is, that even though I have 3 components in 3 columns, for some reason, the first two components are put in the same column. Maybe I don't understand it, but I have thought it over 20 times and it doesn't really makes sense to me. Please help.

Here is some code:

// Frame Setup
        JFrame frame = new JFrame("GridBagLayout_Test");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().setBackground(Color.CYAN);
        frame.setLocation(550, 250);
        frame.setSize(800, 550);

        JPanel startScreen = new JPanel(new GridBagLayout());
        startScreen.setBackground(Color.BLACK);
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.fill = GridBagConstraints.BOTH;

        JButton colorbutton = new JButton("Color");
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        gbc.gridx = 2;
        gbc.gridy = 0;
        colorbutton.setPreferredSize(new Dimension(100, 30));
        startScreen.add(colorbutton, gbc);

        JLabel game_name = new JLabel("LABEL");
        gbc.gridheight = 1;
        gbc.gridwidth = 3;
        gbc.gridx = 0;
        gbc.gridy = 1;
        game_name.setBackground(Color.ORANGE);
        game_name.setOpaque(true);
        game_name.setPreferredSize(new Dimension(100, 30));
        startScreen.add(game_name, gbc);

        JButton start = new JButton("START");
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        gbc.gridx = 1;
        gbc.gridy = 2;
        start.setPreferredSize(new Dimension(100, 30));
        startScreen.add(start, gbc);

        // Show Results
        frame.add(startScreen);
        frame.setVisible(true);

Solution

  • even though I have 3 components in 3 columns, for some reason, the first two components are put in the same column

    Actually from the GridBagLayout point of view you only have two columns.

    gbc.gridwidth = 3;
    

    When you use the gridWidth constraint you are saying you don't have a specific column because it will occupy the space of 3 columns (assuming you actually have 3 columns which you don't). Since you only have 2 components with a gridwidth of 1, you really only have 2 columns.

    That is the first column doesn't have a unique width (because the only component added to the first column spans multiple columns), so where should column 2 start?

    To demonstrate this, change your code to only use the gridx and gridy constraints.

    Then you will see the 3 components in 3 columns on 3 separate lines.

    Next, add back the:

    gbc.gridwidth = 3;
    

    for the "label".

    Then you will see all 3 components in a single column. This is because the gridwidth of 3 will also be used for the "start" button. So effectively the "label" and "start" components don't have a unique column, so only the "color" has a defined column, so you have a grid with a single column.

    Next, add back the:

    gbc.gridwidth = 1;
    

    for the "start" button.

    Then you will see two columns for the buttons and the label will span the two columns. This is because the "start" and "color" has unique columns and the "label" can only span 2 columns (even though you asked it to span 3 columns).

    I'm not sure the exact layout you are trying to accomplish, so I can't give a suggested solution, but hopefully you understand why you really only have 2 columns, not 3.

    Note as a hack you can add a dummy component in the first column, then the label can span 3 columns. The dummy component would be something like:

        JLabel filler = new JLabel("");
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        gbc.gridx = 0;
        gbc.gridy = 1;
        game_name.setPreferredSize(new Dimension(100, 30));
        startScreen.add(filler, gbc);