Java GridBagLayout not working
Asked Answered
K

2

12

I'm trying to use GridBagLayout, but I don't get what I expect and I can't find the error in this code:

public class GridBagEx1 extends JPanel {

    private static final long serialVersionUID = 1L;

    protected void makebutton(String name, GridBagLayout gridbag, GridBagConstraints c) {
        JButton button = new JButton(name);
        gridbag.setConstraints(button, c);
        add(button);
    }

    public void init() {
        GridBagLayout gridbag = new GridBagLayout();
        GridBagConstraints c = new GridBagConstraints();
        setLayout(gridbag);

        c.fill = BOTH;

        c.weightx = 1.0;
        c.weighty = 1.0;

        c.anchor = CENTER;

        c.insets.top = 5;
        c.insets.bottom = 5;
        c.insets.left = 5;
        c.insets.right = 5;

        c.gridx = 0;
        c.gridy = 0;
        c.gridheight = 1;
        c.gridwidth = 2;
        makebutton("Button1", gridbag, c);      

        c.gridx = 2;
        c.gridy = 0;
        c.gridheight = 1;
        c.gridwidth = 1;
        makebutton("Button2", gridbag, c);

        c.gridx = 3;
        c.gridy = 0;
        c.gridheight = 2;
        c.gridwidth = 2;
        makebutton("Button3", gridbag, c);

        c.gridx = 0;
        c.gridy = 1;
        c.gridheight = 1;
        c.gridwidth = 1;
        makebutton("Button4", gridbag, c);

        c.gridx = 1;
        c.gridy = 1;
        c.gridheight = 1;
        c.gridwidth = 2;
        makebutton("Button5", gridbag, c);

        c.gridx = 0;
        c.gridy = 2;
        c.gridheight = 1;
        c.gridwidth = 1;
        makebutton("Button6", gridbag, c);

        c.gridx = 1;
        c.gridy = 2;
        c.gridheight = 1;
        c.gridwidth = 2;
        makebutton("Button7", gridbag, c);

        c.gridx = 3;
        c.gridy = 2;
        c.gridheight = 1;
        c.gridwidth = 1;
        makebutton("Button8", gridbag, c);

        c.gridx = 4;
        c.gridy = 2;
        c.gridheight = 1;
        c.gridwidth = 1;
        makebutton("Button9", gridbag, c);
    }

    public static void main(String args[]) {
        JFrame frame = new JFrame();
        GridBagEx1 ex1 = new GridBagEx1();

        ex1.init();

        frame.add(ex1);
        frame.pack();
        frame.setVisible(true);
    }
}

This picture illustrate what I need:

Programmers love paint

Yellow are button name, red are row and columns.

This is what really happens: Whats wrong here?

Can anyone explain what is wrong in my code?

Kanishakanji answered 28/9, 2014 at 19:20 Comment(10)
I can't explain the issue yet, but have to state that your question is very well presented, thank you and 1+.Czarevna
c.fill = BOTH; should be c.fill = GridBagConstraints.BOTH; and same for c.anchor = CENTER; for the code to compile.Extensor
@Extensor Not if you import static java.awt.GridBagConstraints.*; :-)Owenowena
@GeroldBroser True... true...Extensor
You should try to explain the constraints you'd like to have between your widgets : what is fixed, what will take the remaining space, what should stay aligned and what sizes shoult stay equal, etc...Ingle
Can I interest you in GroupLayout? :)Extensor
No, MigLayout. But touche to Boann and his answer. 1+Czarevna
@Extensor That class is a static importKanishakanji
@Kanishakanji I was talking about a different layout manager.Extensor
That's funny indeed: I managed to get the needed layout by tinkering with the 4 fields associated with the buttons. Then I designed the JPanel according to the needed in WindowsBuilder. In its Quick preview it looks like the needed as well. If I run it via main() it looks like what really happens. Confuses me, too.Owenowena
T
8

The problem is that nothing is persuading the second grid column (gridx=1) to have any width, because there is no component that needs to fit only in the second column. The second column thus has 0 width, so although Button1 does straddle the first two columns, it doesn't look that way because all of its width need is satisfied by the first column; and although Button5 and Button7 straddle the second and third columns, all of their width need is satisfied by the third column.

To fix it you must persuade the buttons which should to be wider (1, 5, 7) to take up more space. Here I added padding to those buttons by setting c.ipadx = 35;. (I also removed the weightx = 1.0 constraint. For reasons I don't quite understand, it didn't work when that was left in.):

screenshot

Source:

public void init() {
    GridBagLayout gridbag = new GridBagLayout();
    GridBagConstraints c = new GridBagConstraints();
    setLayout(gridbag);

    c.fill = c.BOTH;

    //c.weightx = 1.0;
    //c.weighty = 1.0;

    c.anchor = c.CENTER;

    c.insets.top = 5;
    c.insets.bottom = 5;
    c.insets.left = 5;
    c.insets.right = 5;

    c.gridx = 0;
    c.gridy = 0;
    c.gridheight = 1;
    c.gridwidth = 2;
    c.ipadx = 35;
    makebutton("Button1", gridbag, c);

    c.gridx = 2;
    c.gridy = 0;
    c.gridheight = 1;
    c.gridwidth = 1;
    c.ipadx = 0;
    makebutton("Button2", gridbag, c);

    c.gridx = 3;
    c.gridy = 0;
    c.gridheight = 2;
    c.gridwidth = 2;
    c.ipadx = 0;
    makebutton("Button3", gridbag, c);

    c.gridx = 0;
    c.gridy = 1;
    c.gridheight = 1;
    c.gridwidth = 1;
    c.ipadx = 0;
    makebutton("Button4", gridbag, c);

    c.gridx = 1;
    c.gridy = 1;
    c.gridheight = 1;
    c.gridwidth = 2;
    c.ipadx = 35;
    makebutton("Button5", gridbag, c);

    c.gridx = 0;
    c.gridy = 2;
    c.gridheight = 1;
    c.gridwidth = 1;
    c.ipadx = 0;
    makebutton("Button6", gridbag, c);

    c.gridx = 1;
    c.gridy = 2;
    c.gridheight = 1;
    c.gridwidth = 2;
    c.ipadx = 35;
    makebutton("Button7", gridbag, c);

    c.gridx = 3;
    c.gridy = 2;
    c.gridheight = 1;
    c.gridwidth = 1;
    c.ipadx = 0;
    makebutton("Button8", gridbag, c);

    c.gridx = 4;
    c.gridy = 2;
    c.gridheight = 1;
    c.gridwidth = 1;
    c.ipadx = 0;
    makebutton("Button9", gridbag, c);
}

Edit: As pointed out in the comments, the above approach is not suitable because it prevents the layout being resized dynamically. To have the layout expand to fill the size of its container, the weightx and weighty constraints are needed, but then the second column does not get any width.

Here is an attempt at an alternative solution. It's a dirty hack that inserts an invisible component at the bottom of the second column to force the column to have width:

    c.gridx = 1;
    c.gridy = 3;
    c.gridheight = 1;
    c.gridwidth = 1;
    c.insets.set(0, 0, 0, 0);
    c.weighty = 0;
    add(Box.createRigidArea(new Dimension(50, 0)), c);

This copes fairly well when the window is resized because although the component is given a fixed initial size, GridBagLayout scales up it proportionally with the other components. It is still not perfect, though. Maybe there is a better solution but I can't find it.

Tycoon answered 28/9, 2014 at 20:58 Comment(5)
@FilipB.Vondrášek I don't think this one particular case with a specific (quite complex) layout manager sums up and justifies Swing being an abomination. Sure Swing has its cons and pros, but it's not like it's a secret, everyone knows that.Latoya
@FilipB.Vondrášek If only there were a non-abominable alternative.Tycoon
What about JavaFX? Never used that, though.Blunger
@Tycoon Removing weighty,x the button don't resize, if you re-add them this code will not work!Kanishakanji
@Tycoon Another thing, the button don't have a dimension itself, i want that the gridbaglayout assign to them a dimension in base of the jpanel!Kanishakanji
O
2

I managed to design the needed layout without any hack and supporting dynamic resizing by using JGoodies FormLayout:

import java.awt.Component;

import javax.swing.JButton;
import javax.swing.JPanel;

import com.jgoodies.forms.factories.FormFactory;
import com.jgoodies.forms.layout.ColumnSpec;
import com.jgoodies.forms.layout.FormLayout;
import com.jgoodies.forms.layout.RowSpec;

public class FormLayoutPanel extends JPanel
    {
    public FormLayoutPanel()
        {
        setAlignmentY( Component.BOTTOM_ALIGNMENT );
        setAlignmentX( Component.RIGHT_ALIGNMENT );
        setLayout( new FormLayout( new ColumnSpec[] {
            ColumnSpec.decode( "41px:grow" ),
            FormFactory.LABEL_COMPONENT_GAP_COLSPEC,
            ColumnSpec.decode( "25px:grow" ),
            FormFactory.LABEL_COMPONENT_GAP_COLSPEC,
            ColumnSpec.decode( "41px:grow" ),
            FormFactory.LABEL_COMPONENT_GAP_COLSPEC,
            ColumnSpec.decode( "41px:grow" ),
            FormFactory.LABEL_COMPONENT_GAP_COLSPEC,
            ColumnSpec.decode( "41px:grow" ), },
            new RowSpec[] {
                RowSpec.decode( "25px:grow" ),
                FormFactory.LINE_GAP_ROWSPEC,
                RowSpec.decode( "25px:grow" ),
                FormFactory.LINE_GAP_ROWSPEC,
                RowSpec.decode( "25px:grow" ), } ) );

        JButton button1 = new JButton( "1" );
        add( button1, "1, 1, 3, 1, fill, fill" );
        JButton button2 = new JButton( "2" );
        add( button2, "5, 1, fill, fill" );
        JButton button3 = new JButton( "3" );
        add( button3, "7, 1, 3, 3, fill, fill" );
        JButton button4 = new JButton( "4" );
        add( button4, "1, 3, fill, fill" );
        JButton button5 = new JButton( "5" );
        add( button5, "3, 3, 3, 1, fill, fill" );
        JButton button6 = new JButton( "6" );
        add( button6, "1, 5, fill, fill" );
        JButton button7 = new JButton( "7" );
        add( button7, "3, 5, 3, 1, fill, fill" );
        JButton button8 = new JButton( "8" );
        add( button8, "7, 5, fill, fill" );
        JButton button9 = new JButton( "9" );
        add( button9, "9, 5, fill, fill" );
        }
    }
Owenowena answered 9/10, 2014 at 21:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.