Why Does This Gridbaglayout Not Appear as Planned

Why does this GridBagLayout not appear as planned?

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.stack.imgur.com/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.

GridBagLayout not coming out as expected

Well let's start of by saying that whatever modification you make to your GridBagConstraints instance is persisted to any of the following usages of that instance.

So if you do this gbc.gridwidth = 9 make sure to reset it to gbc.gridwidth = 1, otherwise every element added will have a gridwidth of 9 applied to it.
And no need to set gridy = 0 everytime you add a button on the same line, that just adds unnecessary lines of code.

Now I have just cleaned up your Window() code to show you a correct use of the GridBagConstraints and removed the duplicate assigns.
You will have to add your ActionListeners again

public Window() {
Container panel = this.getContentPane();
panel.setLayout(new GridBagLayout());
panel.setSize(1000,1000);

GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weightx = 1;
gbc.weighty = 1;

gbc.gridy = 0; // First row

JButton ordersButton = new JButton("Orders");
gbc.gridx = 0;
panel.add(ordersButton, gbc);

JButton dishesButton = new JButton("Dishes");
gbc.gridx = 1;
panel.add(dishesButton, gbc);

JButton ingredientsButton = new JButton("Ingredients");
gbc.gridx = 2;
panel.add(ingredientsButton, gbc);

JButton suppliersButton = new JButton("Suppliers");
gbc.gridx = 3;
panel.add(suppliersButton, gbc);

JButton staffButton = new JButton("Staff");
gbc.gridx = 4;
panel.add(staffButton, gbc);

JButton dronesButton = new JButton("Drones");
gbc.gridx = 5;
panel.add(dronesButton, gbc);

JButton usersButton = new JButton("Users");
gbc.gridx = 6;
panel.add(usersButton, gbc);

JButton postcodesButton = new JButton("Postcodes");
gbc.gridx = 7;
panel.add(postcodesButton, gbc);

JButton configurationButton = new JButton("Configuration");
gbc.gridx = 8;
panel.add(configurationButton, gbc);

JTextField viewScreen = new JTextField();
gbc.gridx = 0;
gbc.gridy = 1;
gbc.gridwidth = 9;
viewScreen.setPreferredSize(new Dimension(650, 200));
viewScreen.setMinimumSize(new Dimension(650, 200));
panel.add(viewScreen, gbc);
gbc.gridwidth = 1; // Reset the gridwidth

// Third row
JLabel orders1Label = new JLabel("order 1");
gbc.gridx = 1;
gbc.gridy = 2;
panel.add(orders1Label, gbc);
JLabel orders2Label = new JLabel("order 2");
gbc.gridx = 1;
gbc.gridy = 3;
panel.add(orders2Label, gbc);
JLabel dishes1Label = new JLabel("dish 1");
gbc.gridx = 1;
gbc.gridy = 4;
panel.add(dishes1Label, gbc);
JLabel dishes2Label = new JLabel("dish 2");
gbc.gridx = 1;
gbc.gridy = 5;
panel.add(dishes2Label, gbc);

gbc.gridwidth = 4; // Textfield width
JTextField orders1TextField = new JTextField();
gbc.gridx = 2;
gbc.gridy = 2;
panel.add(orders1TextField, gbc);
JTextField orders2TextField = new JTextField();
gbc.gridx = 2;
gbc.gridy = 3;
panel.add(orders2TextField, gbc);
JTextField dishes1TextField = new JTextField();
gbc.gridx = 2;
gbc.gridy = 4;
panel.add(dishes1TextField, gbc);
JTextField dishes2TextField = new JTextField();
gbc.gridx = 2;
gbc.gridy = 5;
panel.add(dishes2TextField, gbc);

orders1TextField.setPreferredSize(new Dimension(400, 20));
orders2TextField.setPreferredSize(new Dimension(400, 20));
dishes1TextField.setPreferredSize(new Dimension(400, 20));
dishes2TextField.setPreferredSize(new Dimension(400, 20));

//Display window
setSize(800,600);
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}

And I got this layout

generated image

The layout is probably not exactly what you wanted, but I hope you can continue your work with this example. ;)

GridBagLayout not working as expected

When setting

gbc.gridx = 1;
gbc.gridy = 0;

for GridBagConstraints, you are not setting absolute co-ordinates like you would if you using absolute positioning. Instead, you are setting the grid cell where the component will reside. In this sample application above, there is only one component so there is only one grid cell so the JButton will be center positioned by default.

To highlight this fact we could add set the anchor to NORTH and add another button, creating 2 grid cells:

gbc.anchor = GridBagConstraints.NORTH;
gbc.weightx = 1.0;
gbc.weighty = 1.0;

gbc.gridx = 1;
gbc.gridy = 0;

panel1.add(new JButton("Hello"), gbc);

gbc.gridx = 2; // now a 2nd cell exists
panel1.add(new JButton("Test"), gbc);

Notice we also set weightx and weighty so that the button could take their positions at the top of the JFrame:

GridBagLayout with 2 NORTH-Anchored Components

GridBagLayout does not display a component

But it can't be seen when a GridBagLayout is set.

Probably because you didn't override the getPreferredSize() method of your component so the preferred size will be (0, 0).

The GridBagLayout will attempt to display the component at its preferred size.

I would guess you would need to use the fill constraint when adding the component so it can be automatically resized to fill the space available in the cell. Read the section from the Swing tutorial on How to Use GridBagLayout for more information and examples.

When I put it in BorderLayout everything looks fine.

When added to the CENTER of a BorderLayout the component will be resized to fill the space available.

GridBagLayout Not Working Properly?

Your code is a mess (sorry), I could spent a lot of time trying to unravel your compound layouts, but it would be easier to just start again. Not saying that you might not consider using a compound layout concept, but I think that's what's got you into such a mess to start with...

So I've basically create a simplified example of what I "guess" your description is asking for...

GridBagLayout

import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

public static void main(String[] args) {
new Test();
}

public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}

JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}

public class TestPane extends JPanel {

public TestPane() {

setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.gridheight = gbc.REMAINDER;
gbc.weightx = 1;
gbc.fill = GridBagConstraints.BOTH;

JTextArea patch = new JTextArea(10, 20);

add(new JScrollPane(patch), gbc);

gbc = new GridBagConstraints();
gbc.gridx = 1;
gbc.gridy = 0;
gbc.fill = GridBagConstraints.HORIZONTAL;
for (int index = 0; index < 6; index++) {
add(new JButton("Button #" + index), gbc);
gbc.gridy++;
}

gbc.gridx = 1;
gbc.anchor = GridBagConstraints.SOUTH;
gbc.weighty = 1;
gbc.fill = GridBagConstraints.HORIZONTAL;
add(new JButton("Play >"), gbc);

}

}

}

With layouts, it's best to start with pen and paper, group the elements you need to together (like the buttons down the right side for example) and devise a plan for how you might lay them out and prototype of view ideas...

Updated

1) How can I have it so that there is space between the TextArea and the buttons, and vertical space on the buttons? I tried using the Insets but I haven't arranged the numbers in a correct way yet.

insets is the correct way to go...

gbc = new GridBagConstraints();
gbc.gridx = 1;
gbc.gridy = 0;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.insets = new Insets(2, 8, 2, 4);
gbc.anchor = GridBagConstraints.NORTH;
for (int index = 0; index < 6; index++) {
core.add(new JButton("Button #" + index), gbc);
gbc.gridy++;
}

2) I would like the "Play" button at the center-bottom of the screen, and have it be larger

You "could" do this with GridBagLayout, but I decided not to, as it can cause some issues if you're not careful with how your setup the constraints for the other components, so instead, I used a combination of BorderLayout and GridBagLayout.

To make the "play" button larger, you could modify the font or adjust the button's margins...

playButton.setMargin(new Insets(12, 12, 12, 12));

depending on the effect you're after

Sample Image

public class TestPane extends JPanel {

public TestPane() {

setLayout(new BorderLayout(0, 4));

JPanel core = new JPanel(new GridBagLayout());

GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.gridheight = GridBagConstraints.REMAINDER;
gbc.weightx = 1;
gbc.weighty = 1;
gbc.fill = GridBagConstraints.BOTH;

JTextArea patch = new JTextArea(10, 20);

core.add(new JScrollPane(patch), gbc);

gbc = new GridBagConstraints();
gbc.gridx = 1;
gbc.gridy = 0;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.insets = new Insets(2, 8, 2, 4);
gbc.anchor = GridBagConstraints.NORTH;
for (int index = 0; index < 6; index++) {
core.add(new JButton("Button #" + index), gbc);
gbc.gridy++;
}

add(core);
JButton playButton = new JButton("Play >");
playButton.setMargin(new Insets(12, 12, 12, 12));
add(playButton, BorderLayout.SOUTH);

}

}

GridBagLayout not showing JTextArea, and showing panel in center

Don't forget weights and anchors:

    c.weightx = 1.0;
c.weighty = 1.0;
c.anchor = GridBagConstraints.NORTHWEST;

Edit:
Example of adding row and column values to the JTextArea:

    controlPanel.add(new JButton("Play"));
controlPanel.add(new JButton("Pause"));
controlPanel.add(new JSpinner());

JTextArea textArea = new JTextArea(20, 40);

c.gridx = 0;
c.gridy = 0;
c.gridheight = 3;
c.gridwidth = 3;
c.weightx = 1.0;
c.weighty = 1.0;
c.anchor = GridBagConstraints.NORTHWEST;
mainPanel.add(new JScrollPane(textArea), c);

java GridBagLayout not working?

However, the result was horizontal. Does anyone why this happened?

Probably because the default layout manager of a JPanel is the FlowLayout and you didn't change the layout manager when you created the panel. The FlowLayout displays components horizontally.

When you create the panel you also need:

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

GridBagLayout gridwidth doesn't work as expected

I know how you feel... It seems GridBagLayout reduces the width of columns to 0 when they are not filled by 1x1 component. I don't know if the following is the most efficient solution, but it works (by adding two dummy JPanel to "inflate" columns 1 and 2):

JFrame test = new JFrame();
test.setSize(800,800);
test.setLayout(new GridBagLayout());
test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

GridBagConstraints c;

c = new GridBagConstraints();
c.gridx=0;
c.gridy=0;
c.fill = GridBagConstraints.BOTH;
c.weightx = 1;
c.weighty = 1;
test.add(new JButton("A"), c);

c = new GridBagConstraints();
c.gridx=0;
c.gridy=1;
c.gridwidth=2;
c.fill = GridBagConstraints.BOTH;
c.weightx = 1;
c.weighty = 1;
test.add(new JButton("B"), c);

c = new GridBagConstraints();
c.gridx=1;
c.gridy=0;
c.gridwidth=2;
c.gridheight=1;
c.fill = GridBagConstraints.BOTH;
c.weightx = 2;
c.weighty = 2;
test.add(new JButton("C"), c);

c = new GridBagConstraints();
c.gridx=1;
c.gridy=2;
c.gridwidth=1;
c.gridheight=0;
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 1;
c.weighty = 0;
test.add(new JPanel(), c);

c = new GridBagConstraints();
c.gridx=2;
c.gridy=3;
c.gridwidth=1;
c.gridheight=0;
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 1;
c.weighty = 0;
test.add(new JPanel(), c);

test.setVisible(true);

JComboBox not appearing in GridBagLayout

After many tries I managed to fix it.

I removed the GridBagLayout.RELATIVE attribute and changed it to 1 in the gbc4cmb and it worked!

GridBagConstraints gbc4cmb = (GridBagConstraints) gbc4f.clone(); //ComboBox 
gbc4cmb.anchor = GridBagConstraints.NORTHWEST;
gbc4cmb.insets = new Insets(1, 1, 1, 1);
gbc4cmb.gridwidth = 1;


Related Topics



Leave a reply



Submit