3

I've discovered recently strange thing in this code:

import java.awt.Color;
import java.awt.Container;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.io.IOException;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;


public class Test {

    public static void main(String [] args) throws IOException {
        final JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JPanel panel = new JPanel();
        panel.setLayout(new GridBagLayout());

        GridBagConstraints gbc = new GridBagConstraints();

        gbc.insets.top = 5;
        gbc.insets.right = 5;

        add(0, 0, 1, 1, 2, 1, GridBagConstraints.BOTH, GridBagConstraints.CENTER, gbc, panel, createPanel());
        add(2, 0, 1, 1, 2, 1, GridBagConstraints.BOTH, GridBagConstraints.CENTER, gbc, panel, createPanel());
        add(0, 1, 1, 1, 2, 1, GridBagConstraints.BOTH, GridBagConstraints.CENTER, gbc, panel, createPanel());
        add(2, 1, 1, 1, 2, 1, GridBagConstraints.BOTH, GridBagConstraints.CENTER, gbc, panel, createPanel());
        add(0, 2, 1, 1, 1, 1, GridBagConstraints.BOTH, GridBagConstraints.CENTER, gbc, panel, createPanel());
        add(1, 2, 1, 1, 2, 1, GridBagConstraints.BOTH, GridBagConstraints.CENTER, gbc, panel, createPanel());
        add(3, 2, 1, 1, 1, 1, GridBagConstraints.BOTH, GridBagConstraints.CENTER, gbc, panel, createPanel());
        add(0, 3, 1, 1, 1, 1, GridBagConstraints.BOTH, GridBagConstraints.CENTER, gbc, panel, createPanel());
        add(1, 3, 1, 1, 2, 1, GridBagConstraints.BOTH, GridBagConstraints.CENTER, gbc, panel, createPanel());
        add(3, 3, 1, 1, 1, 1, GridBagConstraints.BOTH, GridBagConstraints.CENTER, gbc, panel, createPanel());
        add(0, 4, 1, 1, 1, 1, GridBagConstraints.BOTH, GridBagConstraints.CENTER, gbc, panel, createPanel());
        add(1, 4, 1, 1, 2, 1, GridBagConstraints.BOTH, GridBagConstraints.CENTER, gbc, panel, createPanel());
        add(3, 4, 1, 1, 1, 1, GridBagConstraints.BOTH, GridBagConstraints.CENTER, gbc, panel, createPanel());
        add(0, 5, 1, 1, 4, 1, GridBagConstraints.BOTH, GridBagConstraints.CENTER, gbc, panel, createPanel());

        frame.setContentPane(panel);

        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    private static void add(int gridx, int gridy, int weightx, int weighty, int gridw, int gridh, int fill, int anchor, GridBagConstraints gbc, Container container, JComponent component) {
        gbc.gridx = gridx;
        gbc.gridy = gridy;
        gbc.weightx = weightx;
        gbc.weighty = weighty;
        gbc.gridwidth = gridw;
        gbc.gridheight = gridh;
        gbc.fill = fill;
        gbc.anchor = anchor;

        component.add(Box.createHorizontalStrut(5));
        component.add(new JLabel("(" + gridx + "; " + gridy + ")"));
        component.add(Box.createHorizontalStrut(5));
        component.add(new JLabel("gridwidth = " + gridw));
        component.add(Box.createHorizontalStrut(5));

        container.add(component, gbc);
    }

    private static JPanel createPanel() {
        JPanel panel1 = new JPanel();
        panel1.setBackground(Color.WHITE);
        panel1.setBorder(BorderFactory.createLineBorder(Color.RED));

        return panel1;
    }
}

And how it looks on run:

java_weird

There are coordinates in brackets and gridwidth of each panel. As you can see from last row, the global gridwidth is 4. Rows 3-5 (y=2, y=3, y=4) in column 1 (x=0) have gridwidth equal to 1. But in first two rows the first column has gridwidth equal to 2, and it supposed to be divided in a middle of frame, but us isn't. Why?

Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
SeniorJD
  • 6,946
  • 4
  • 36
  • 53
  • I'm not sure I understand the use case or the question, but note that GBL typically won't assign any more space to a cell than it calculates the cell actually needs. To put that another way, increasing the gridwidth of a cell to 2 will possibly arrange the cell a little wider to accommodate two cells that are gridwidth 1 and aligned with it, but not otherwise. See also [Why does this GridBagLayout not appear as planned?](http://stackoverflow.com/q/27371956/418556) which was subject to the same basic problem. – Andrew Thompson Sep 30 '15 at 09:03
  • What about 3-3, 3-3, 2-2-2, 2-2-2, 2-2-2? – Joop Eggen Sep 30 '15 at 09:07
  • @AndrewThompson Do you mean, that if the width of (0; 0) cell get less than actual min or preferred width of that cell, it will get wider? Only in that case? – SeniorJD Sep 30 '15 at 09:08
  • @JoopEggen The same. Actually, I discovered this issue in that case, and then tried to simplify down like my example is, but issue remained. – SeniorJD Sep 30 '15 at 09:09
  • This comes from the fact that the column 1 (starting from 0) is not specified anywhere and is therefore considered to have a width of 0. You don't define the width of the column 2 either. So even traditional workarounds won't work. I recommend using other layouts, like miglayout for instance. – Olivier Grégoire Sep 30 '15 at 09:41

1 Answers1

1

What I found by myself:

public class Test {

    public static void main(String [] args) throws IOException {
        final JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JPanel panel = new JPanel();
        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));

        GridBagConstraints gbc = new GridBagConstraints();

        gbc.insets.top = 5;
        gbc.insets.right = 5;

        JPanel topPanel = new JPanel();
        topPanel.setLayout(new GridBagLayout());
        JPanel bottomPanel = new JPanel();
        bottomPanel.setLayout(new GridBagLayout());

        add(0, 0, 1, 1, 1, 1, GridBagConstraints.BOTH, GridBagConstraints.CENTER, gbc, topPanel, createPanel());
        add(1, 0, 1, 1, 2, 1, GridBagConstraints.BOTH, GridBagConstraints.CENTER, gbc, topPanel, createPanel());
        add(0, 0, 1, 1, 1, 1, GridBagConstraints.BOTH, GridBagConstraints.CENTER, gbc, bottomPanel, createPanel());
        add(1, 0, 1, 1, 1, 1, GridBagConstraints.BOTH, GridBagConstraints.CENTER, gbc, bottomPanel, createPanel());
        add(2, 0, 1, 1, 1, 1, GridBagConstraints.BOTH, GridBagConstraints.CENTER, gbc, bottomPanel, createPanel());
        add(0, 2, 1, 1, 3, 1, GridBagConstraints.BOTH, GridBagConstraints.CENTER, gbc, bottomPanel, createPanel());

        panel.add(topPanel);
        panel.add(bottomPanel);

        frame.setContentPane(panel);

        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    private static void add(int gridx, int gridy, int weightx, int weighty, int gridw, int gridh, int fill, int anchor, GridBagConstraints gbc, Container container, JComponent component) {
        gbc.gridx = gridx;
        gbc.gridy = gridy;
        gbc.weightx = weightx;
        gbc.weighty = weighty;
        gbc.gridwidth = gridw;
        gbc.gridheight = gridh;
        gbc.fill = fill;
        gbc.anchor = anchor;

        component.add(Box.createHorizontalStrut(5));
        component.add(new JLabel("(" + gridx + "; " + gridy + ")"));
        component.add(Box.createHorizontalStrut(5));
        component.add(new JLabel("gridwidth = " + gridw));
        component.add(Box.createHorizontalStrut(5));

        container.add(component, gbc);
    }

    private static JPanel createPanel() {
        JPanel panel1 = new JPanel();
        panel1.setBackground(Color.WHITE);
        panel1.setBorder(BorderFactory.createLineBorder(Color.RED));

        return panel1;
    }
}

Result looks like:

java weird

What I've done: divided the content pane into two separate panels - top (with a single row which has two equally divided cells) and bottom (with two rows: one has 3 cells and another has 1 single wide cell). Content pane now has the BoxLayout instead of GBL, and it works as expected. But I'm disappointed about GridBagLayout, it was the perfect layout for me before now.

SeniorJD
  • 6,946
  • 4
  • 36
  • 53
  • you cant divide 100 / 3 without ..., LayoutManager calculates it getPreferredSize quite correctly, rest (in pixels) is "emty border", this issue is possible to see on resize too, MigLayout can do that correctly – mKorbel Sep 30 '15 at 11:31
  • Don't you have an alignment issue on the right side of the first line? – Olivier Grégoire Sep 30 '15 at 12:06