GridBagLayout gridding not working
Asked Answered
T

4

5

I am trying to create the following GUI:

enter image description here

but the GUI that I make is:

enter image description here

What my grid looks like:

image: THE GRIDLAYOUT FOR THIS

I don't understand why I am getting this output since I have drawn a diagram to aid the code and it seems to work out.

The method addComp adds adds the input component to the input panel at a given (x, y) position and at a given component width and height.

Code:

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

public class GUIError extends JFrame {

    //initialise all the components
    JPanel mainPanel = new JPanel();
    JTextField txtDisplay = new JTextField();
    JButton btnA = new JButton("A");
    JButton btnB = new JButton("B");
    JButton btnC = new JButton("C");
    JButton btnD = new JButton("D");
    JButton btnE = new JButton("E");
    JButton btnF = new JButton("F");
    JButton btnWA = new JButton("WA");
    JButton btnWB = new JButton("WB");
    JButton btnWC = new JButton("WC");
    JButton btnWD = new JButton("WD");

    private void addComp(JPanel panel, JComponent comp, int xPos, int yPos, int compWidth, int compHeight) {

        GridBagConstraints gridConstraints = new GridBagConstraints();

        gridConstraints.gridx = xPos;
        gridConstraints.gridy = yPos;
        gridConstraints.gridwidth = compWidth;
        gridConstraints.gridheight = compHeight;
        gridConstraints.weightx = 0.5;
        gridConstraints.weighty = 0.5;
        gridConstraints.insets = new Insets(5, 5, 5, 5);
        gridConstraints.anchor = GridBagConstraints.CENTER;
        gridConstraints.fill = GridBagConstraints.BOTH;

        panel.add(comp, gridConstraints);

    }


    public static void main(String[] args) {
        try {
            for (UIManager.LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        }
        catch (Exception e) { }

        SwingUtilities.invokeLater(new Runnable() {

            public void run() {

                // create frame
                JFrame frame = new JFrame("Calculator");
                frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                frame.setLocationRelativeTo(null);
                Container c = frame.getContentPane();

                // create GUI within frame              
                new GUIError(c);

                // finish frame definition
                frame.pack();
                frame.setResizable(false);
                frame.setVisible(true);

            }

        });
    }

    public GUIError(Container cont) {

        cont.setPreferredSize(new Dimension(610, 250));

        // parent panel containes every other panel
        mainPanel.setLayout(new GridBagLayout());

        // text display
        txtDisplay.setEditable(false);
        addComp(mainPanel, txtDisplay, 0, 0, 12, 2); // width 16, height 2


        addComp(mainPanel, btnA, 0, 2, 2, 1);
        addComp(mainPanel, btnB, 2, 2, 2, 1);
        addComp(mainPanel, btnC, 4, 2, 2, 1);
        addComp(mainPanel, btnD, 6, 2, 2, 1);
        addComp(mainPanel, btnE, 8, 2, 2, 1);
        addComp(mainPanel, btnF, 10, 2, 2, 1);
        addComp(mainPanel, btnWA, 0, 3, 3, 1);
        addComp(mainPanel, btnWB, 3, 3, 3, 1);
        addComp(mainPanel, btnWC, 6, 3, 3, 1);
        addComp(mainPanel, btnWD, 9, 3, 3, 1);

        cont.add(mainPanel);
    }
}
Trichomoniasis answered 18/6, 2014 at 16:47 Comment(6)
GBC are column based, +1 for question and SSCCE/MCVE, reason why MigLayout (e.i.) are developedBradley
Don't think you can achieve this with just 1 panel. gridwidth can't specify "half a grid" as far as I know. I think the best choice would be to either use a different layout, or separate your components into different panels (main panel contains a field at the top and 2 panels below (side by side). each subpanel has 2 panels: one for the 3 smaller buttons, one with the 2 bigger buttons below it)Barbabra
I haven't specified half a grid using gridwidth. The first line of buttons are gridwidth = 2 and the third line of buttons are gridwidth = 3. I don't understand what you mean by 3 smaller and 2 bigger buttons at the bottom? The grid I have also linked displays the grid I have used in this situation. The second row of buttons are all the same size, the third row of buttons are all the same size. I don't understand why this wouldn't work with GridBagLayout.Trichomoniasis
@Trichomoniasis Look at the results you are asking for; you want WA and WB to take up the same amount of space as 3 other buttons. As you can see by the results you are getting, your components are appearing to lock into place (aligned with everything else). You have 6 grid spaces across due to your small buttons; you want WA to take up 1 1/2 of the gridspace below, and WB to take up another 1 1/2 (same with WC and WD). In code, you did not try to take up half a grid, but the results you are asking for requires it. This can be done by switching layouts or separating with panelsBarbabra
I shall post an answer explaining, along with a solution. Give me a secondBarbabra
@Bradley could you elaborate on GBC are column based? It sounds like an explanation of a problem I noticed...Ten
G
5

It can easily be achieved by using GridBagLayout as seen in this example presented below. You simply need to take two JPanel one each for each ROW. Both using GridBagLayout, and add components to the first row, with weightx = 0.16 since each JButton is suppose to take this much area, and for the second row weightx = 0.25 since, this is the area occupied by each JButton along the X direction

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

public class GridBagExample {
    private static final int SIZE = 10;
    private JButton[] buttons;
    private GridBagConstraints gbc;

    public GridBagExample() {
        buttons = new JButton[SIZE];
        gbc = new GridBagConstraints();
        gbc.insets = new Insets(5, 5, 5, 5);
    }

    private void createAndDisplayGUI() {
        JFrame frame = new JFrame("Grid Game");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

        JPanel contentPane = new JPanel();
        contentPane.setLayout(new GridLayout(2, 1, 5, 5));
        contentPane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));

        JPanel topPanel = new JPanel();
        JTextField textField = new JTextField(10);
        //topPanel.add(textField);

        JPanel buttonPanel = new JPanel(new GridLayout(2, 1, 5, 5));
        JPanel headerPanel = new JPanel(new GridBagLayout());
        buttons[0] = new JButton("A");
        addComp(headerPanel, buttons[0], 0, 0, 0.16, 1.0, 1, 1, GridBagConstraints.BOTH);        
        buttons[1] = new JButton("B");
        addComp(headerPanel, buttons[1], 1, 0, 0.16, 1.0, 1, 1, GridBagConstraints.BOTH);
        buttons[2] = new JButton("C");
        addComp(headerPanel, buttons[2], 2, 0, 0.16, 1.0, 1, 1, GridBagConstraints.BOTH);
        buttons[3] = new JButton("D");
        addComp(headerPanel, buttons[3], 3, 0, 0.16, 1.0, 1, 1, GridBagConstraints.BOTH);
        buttons[4] = new JButton("E");
        addComp(headerPanel, buttons[4], 4, 0, 0.16, 1.0, 1, 1, GridBagConstraints.BOTH);
        buttons[5] = new JButton("F");
        addComp(headerPanel, buttons[5], 5, 0, 0.16, 1.0, 1, 1, GridBagConstraints.BOTH);

        JPanel footerPanel = new JPanel(new GridBagLayout());
        buttons[6] = new JButton("WA");
        addComp(footerPanel, buttons[6], 0, 0, 0.25, 1.0, 1, 1, GridBagConstraints.BOTH);
        buttons[7] = new JButton("WB");
        addComp(footerPanel, buttons[7], 1, 0, 0.25, 1.0, 1, 1, GridBagConstraints.BOTH);
        buttons[8] = new JButton("WC");
        addComp(footerPanel, buttons[8], 2, 0, 0.25, 1.0, 1, 1, GridBagConstraints.BOTH);
        buttons[9] = new JButton("WD");
        addComp(footerPanel, buttons[9], 3, 0, 0.25, 1.0, 1, 1, GridBagConstraints.BOTH);
        buttonPanel.add(headerPanel);
        buttonPanel.add(footerPanel);

        contentPane.add(textField);
        contentPane.add(buttonPanel);

        frame.setContentPane(contentPane);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    private void addComp(JPanel panel, JComponent comp, int x, int y,
                                    double wx, double wy, int gw, int gh, int fill) {
        gbc.gridx = x;
        gbc.gridy = y;
        gbc.weightx = wx;
        gbc.weighty = wy;
        gbc.gridwidth = gw;
        gbc.gridheight = gh;
        gbc.fill = fill;

        panel.add(comp, gbc);
    }

    public static void main(String... args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new GridBagExample().createAndDisplayGUI();
            }
        });
    }
}

OUTPUT: GRIDBAGLAYOUT:

gridbagexample

The same output can be achieved by GridLayout, if GridBagLayout is not a necessity in this case, as cited in the below example:

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

public class GridBagExample {
    private static final int SIZE = 10;
    private JButton[] buttons;

    public GridBagExample() {
        buttons = new JButton[SIZE];
    }

    private void createAndDisplayGUI() {
        JFrame frame = new JFrame("Grid Game");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

        JPanel contentPane = new JPanel();
        contentPane.setLayout(new GridLayout(2, 1, 5, 5));
        contentPane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));

        JPanel topPanel = new JPanel();
        JTextArea tArea = new JTextArea(5, 30);
        JScrollPane scroller = new JScrollPane();
        scroller.setViewportView(tArea);
        topPanel.add(scroller);

        JPanel buttonPanel = new JPanel(new GridLayout(2, 1, 5, 5));
        JPanel headerPanel = new JPanel(new GridLayout(1, 0, 5, 5));
        buttons[0] = new JButton("A");
        headerPanel.add(buttons[0]);
        buttons[1] = new JButton("B");
        headerPanel.add(buttons[1]);
        buttons[2] = new JButton("C");
        headerPanel.add(buttons[2]);
        buttons[3] = new JButton("D");
        headerPanel.add(buttons[3]);
        buttons[4] = new JButton("E");
        headerPanel.add(buttons[4]);
        buttons[5] = new JButton("F");
        headerPanel.add(buttons[5]);
        JPanel footerPanel = new JPanel(new GridLayout(1, 0, 5, 5));
        buttons[6] = new JButton("WA");
        footerPanel.add(buttons[6]);
        buttons[7] = new JButton("WB");
        footerPanel.add(buttons[7]);
        buttons[8] = new JButton("WC");
        footerPanel.add(buttons[8]);
        buttons[9] = new JButton("WD");
        footerPanel.add(buttons[9]);
        buttonPanel.add(headerPanel);
        buttonPanel.add(footerPanel);

        contentPane.add(topPanel);
        contentPane.add(buttonPanel);

        frame.setContentPane(contentPane);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    public static void main(String... args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new GridBagExample().createAndDisplayGUI();
            }
        });
    }
}

OUTPUT: GRIDLAYOUT: GridBagExample

Guarino answered 18/6, 2014 at 18:3 Comment(0)
E
5

Normally I'd make separate panels, but hey, who doesn't like a challenge?

The problem is that some of the columns are not well-defined for GBL (there's no single component defining its width), so button WA doesn't know how far out to go to cover half of button B, etc.

So, I added some zero-width spacers in the columns that make up the needed sections.

All in one panel:

enter image description here

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

public class GridBagDemo3 implements Runnable
{
  private JPanel panel;

  public static void main(String[] args)
  {
    SwingUtilities.invokeLater(new GridBagDemo3());
  }

  public void run()
  {
    JTextArea text = new JTextArea(10,10);
    JButton btnA = new JButton("A");
    JButton btnB = new JButton("B");
    JButton btnC = new JButton("C");
    JButton btnD = new JButton("D");
    JButton btnE = new JButton("E");
    JButton btnF = new JButton("F");
    JButton btnWA = new JButton("WA");
    JButton btnWB = new JButton("WB");
    JButton btnWC = new JButton("WC");
    JButton btnWD = new JButton("WD");

    panel = new JPanel(new GridBagLayout());

    add(text,   0,0, 12,1);
    add(btnA,   0,1, 2,1);
    add(btnB,   2,1, 2,1);
    add(btnC,   4,1, 2,1);
    add(btnD,   6,1, 2,1);
    add(btnE,   8,1, 2,1);
    add(btnF,  10,1, 2,1);
    add(btnWA,  0,2, 3,1);
    add(btnWB,  3,2, 3,1);
    add(btnWC,  6,2, 3,1);
    add(btnWD,  9,2, 3,1);

    // SPACERS: define the 2 columns that button B spans
    //          so that WA and WB can split B, and same for button E
    add(null,   2,2, 1,1);
    add(null,   3,2, 1,1);
    add(null,   8,2, 1,1);
    add(null,   9,2, 1,1);

    JFrame frame = new JFrame("Grig Bag");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.getContentPane().add(panel);
    frame.pack();
    frame.setVisible(true);
  }

  private void add(Component comp, int x, int y, int colspan, int rowspan)
  {
    GridBagConstraints gbc = new GridBagConstraints();
    gbc.gridx = x;
    gbc.gridy = y;
    gbc.gridwidth = colspan;
    gbc.gridheight = rowspan;
    gbc.weighty = .1;
    gbc.anchor = GridBagConstraints.CENTER;
    gbc.fill = GridBagConstraints.BOTH;
    gbc.insets = new Insets(5,5,5,5);

    if (comp != null)
    {
      gbc.weightx = 1;
    }
    else
    {
      comp = Box.createHorizontalGlue();
      gbc.fill = GridBagConstraints.NONE;
      gbc.weightx = 0.1;
      gbc.weighty = 0;
    }

    panel.add(comp, gbc);
  }
}
Ehrlich answered 18/6, 2014 at 19:1 Comment(0)
B
4

@Matthieu wrote -

could you elaborate on GBC are column based? It sounds like an explanation of a problem I noticed...

I think that this way is GridBagLayout designed, I'm always using the JLabels (without the Borders:-) as an matrix ...

enter image description here

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

public class CopyTextNorthPanel extends JPanel {

    private static final long serialVersionUID = 1L;
    private JLabel hidelLabel;
    private JLabel firstLabel;
    private JTextField firstText;

    public CopyTextNorthPanel() {

        setLayout(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();
        setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
        for (int k = 0; k < 50; k++) {
            hidelLabel = new JLabel("     ");
            hidelLabel.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
            gbc.fill = GridBagConstraints.HORIZONTAL;
            gbc.weightx = 0.5;
            gbc.weighty = 0.5;
            gbc.gridx = k;
            gbc.gridy = 0;
            add(hidelLabel, gbc);
        }
        for (int k = 0; k < 5; k++) {
            firstLabel = new JLabel("Testing Label : ", SwingConstants.RIGHT);
            firstLabel.setFont(new Font("Serif", Font.BOLD, 20));
            firstLabel.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
            gbc.fill = GridBagConstraints.HORIZONTAL;
            gbc.insets = new Insets(0, 0, 5, 0);
            gbc.gridx = 0;
            gbc.gridwidth = 8;
            gbc.gridy = k + 1;
            add(firstLabel, gbc);
        }
        for (int k = 0; k < 5; k++) {
            firstText = new JTextField("Testing TextField");
            firstText.setFont(new Font("Serif", Font.BOLD, 20));
            firstText.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
            gbc.fill = GridBagConstraints.HORIZONTAL;
            gbc.insets = new Insets(0, 0, 5, 0);
            gbc.gridx = 9;
            gbc.gridwidth = k + 8;
            gbc.gridy = k + 1;
            add(firstText, gbc);
        }
        for (int k = 0; k < 5; k++) {
            firstLabel = new JLabel("Testing Label : ", SwingConstants.RIGHT);
            firstLabel.setFont(new Font("Serif", Font.BOLD, 20));
            firstLabel.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
            gbc.fill = GridBagConstraints.HORIZONTAL;
            gbc.insets = new Insets(0, 0, 5, 0);
            gbc.gridx = 20 + k;
            gbc.gridwidth = 8;
            gbc.gridy = k + 1;
            add(firstLabel, gbc);
        }
        for (int k = 0; k < 5; k++) {
            firstText = new JTextField("Testing TextField");
            firstText.setFont(new Font("Serif", Font.BOLD, 20));
            firstText.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
            gbc.fill = GridBagConstraints.HORIZONTAL;
            gbc.insets = new Insets(0, 0, 5, 0);
            gbc.gridx = 29 + k;
            gbc.gridwidth = 21 - k;
            gbc.gridy = k + 1;
            add(firstText, gbc);
        }
    }
}
Bradley answered 28/8, 2015 at 18:4 Comment(0)
A
3

if you are still interested to understand your error: grid' layout isn't FlowLayout, you can't simply add component and it gonna draw object the same moment program reads it. In case of grid, virtual machine first read all objects and than build grid, the amount of columns is determined in base of those rows which has biggest number of columns. So, you had good idea to prefer 12 columns (thus you avoid creation of new "Panel" and spare system resources), but to do it right you simply should have add 12 empty spaces(not just empty but also with zero size) in one of the rows

    // text display
    txtDisplay.setEditable(false);
    addComp(mainPanel, txtDisplay, 0, 0, 12, 2); // width 16, height 2



    //now go with empty spaces
    for(int i=0;i<12;i++){
        GridBagConstraints gridConstraints = new GridBagConstraints();
        gridConstraints.gridx = i;    //12 times "i"
        gridConstraints.gridy = 1;  //you left y=1 empty, so why don't use it
        gridConstraints.gridwidth = 1;  //one column = one space in grid
        gridConstraints.gridheight = 0;  //we don't want it to occupied any space
        gridConstraints.weightx = 0.5;
        gridConstraints.weighty = 0.5;
        gridConstraints.insets = new Insets(0, 0, 0, 0); //same reason, we don't want it to occupied any space
        gridConstraints.anchor = GridBagConstraints.CENTER;
        gridConstraints.fill = GridBagConstraints.BOTH ;

        mainPanel.add(Box.createHorizontalGlue(), gridConstraints);
    }


    addComp(mainPanel, btnA, 0, 2, 2, 1);
    addComp(mainPanel, btnB, 2, 2, 2, 1);
    addComp(mainPanel, btnC, 4, 2, 2, 1);
    addComp(mainPanel, btnD, 6, 2, 2, 1);
    addComp(mainPanel, btnE, 8, 2, 2, 1);
    addComp(mainPanel, btnF, 10, 2, 2, 1);
    addComp(mainPanel, btnWA, 0, 3, 3, 1);
    addComp(mainPanel, btnWB, 3, 3, 3, 1);
    addComp(mainPanel, btnWC, 6, 3, 3, 1);
    addComp(mainPanel, btnWD, 9, 3, 3, 1);
Asyut answered 18/6, 2014 at 20:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.