Does GridBagLayout require placeholder panels for empty cells? - java

I made a simple GridBagLayout which adds buttons in the cells (0,0), (1,0), and (0,1).
JPanel panelMain = new JPanel(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.gridx = 0;
c.gridy = 0;
panelMain.add(new JButton("0,0"),c);
c.gridx = 1;
c.gridy = 0;
panelMain.add(new JButton("1,0"),c);
c.gridx = 0;
c.gridy = 1;
panelMain.add(new JButton("0,1"),c);
I was happy to see the resultant UI:
I want to add a JButton in a cell that is not connected to the existing cells. I want it to be separated by an empty space. When I try this, the new JButton is lumped in next to the others. Here is the addition:
JPanel panelMain = new JPanel(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.gridx = 0;
c.gridy = 0;
panelMain.add(new JButton("0,0"),c);
c.gridx = 1;
c.gridy = 0;
panelMain.add(new JButton("1,0"),c);
c.gridx = 0;
c.gridy = 1;
panelMain.add(new JButton("0,1"),c);
c.gridx = 3;
c.gridy = 0;
panelMain.add(new JButton("3,0"),c);
The output:
The JButton("3,0") is displaying at the cell (2,0). Do I need to use an empty JPanel as a place holder in the cell (2,0)? More importantly, why is this happening?

The layout does not know what should be the width to be left at 2,0 unless there is a component placed in the gridx = 2. By the time you complete the UI, if any component gets placed, it should look fine. For e.g.:
In other case you may add empty JPanel with background color matching to the background color of the container.

Do I need to use an empty JPanel as a place holder in the cell (2,0)?
You can use an "insets" grid bag constraint to give space between components. Read the Swing tutorial on How to Use GridBagLayout for more information on the inset constraint.
Or, if you want to have a place holder then you can use a Box.createHorizontalStrut(...) to easily specify the width.
More importantly, why is this happening?
Cells don't have a size unless there is a component in the cell. Each cell is independent of one another so what size would you expect cell (2,0) to be?

Related

components are separated when they are suppose to be in succession vertically

I want the image and the title (JLabel) to both me centered and be at the top of the page but instead the image is at the top of the page and centered but the title is 3/4ths of the way down the page and centered.
GridBagConstraints c = new GridBagConstraints();
c.anchor = GridBagConstraints.NORTH;
c.insets = new Insets(10, 0, 0, 0);
c.weighty = 1;
c.gridy = 0;
panel.add(image,c);
c.gridy = 1;
panel.add(title, c);
c.weighty = 1;
c.gridy = 0;
panel.add(image,c);
c.gridy = 1;
panel.add(title, c);
You don't reset the "weighty" constraint so it is used for both components. Therefore, the "extra" space in the frame is allocated equally to each component. So you see the extra space between the two components.
Add a Border to each component and you will see the actual size of each component.
The solution is to assign set the "weighty" constraint to only the second component so the first component is displayed at its preferred size.
//c.weighty = 1;
c.gridy = 0;
panel.add(image,c);
c.gridy = 1;
c.weighty = 1;
panel.add(title, c);

Java GridBadLayout positioning

I would be grateful for any help/suggestion regarding my problem. I attached the image of my simple program which shows that the positioning of the components seems a bit off. My question is - why the ComboBox From... as well as TextField Enter value here... start so far off of the left corner? I've given gridx=0 so it positions the component on the very edge of the window, but components start some pixels off from the edge. How can I fix it?
Also, what do I need to do/consider to remove dependency of the rows on each other? I mean how to position components anywhere I want in one row without effecting the position of other components in another row. Thank you!
Piece of Code:
JPanel container = new JPanel();
container.setLayout(new GridBagLayout());
getContentPane().add(container, BorderLayout.NORTH);
TitledBorder outputCenter;
GridBagConstraints c = new GridBagConstraints();
label = new JLabel("Choose measure system to convert");
label.setFont(new Font("Times New Roman", Font.PLAIN, 20));
c.gridx = 1;
c.gridy = 0;
c.gridwidth = 2;
c.insets = new Insets(10, 0, 20, 0);
container.add(label, c);
fromList = new JComboBox<String>(convertFrom);
c.gridx = 0;
c.gridy = 1;
c.gridwidth =1;
c.ipadx = 20;
c.anchor = GridBagConstraints.LINE_START;
container.add(fromList, c);
toList = new JComboBox<String>(convertTo);
c.gridx = 1;
c.gridy = 1;
c.gridwidth = 1;
c.ipadx = 20;
container.add(toList, c);
//Field where user enters the value to be converted
input = new JTextField("Enter value here...");
input.setPreferredSize(new Dimension(150,30));;
input.setEditable(true);
input.setBackground(Color.WHITE);
input.setBorder(BorderFactory.createLineBorder(Color.BLACK));
input.addMouseListener(new MouseAdapter(){
public void mouseClicked(MouseEvent e){
input.setText("");}});
c.gridx = 0;
c.gridy = 2;
c.gridwidth = 1;
c.ipady = 20;
container.add(input, c);
//The area where the output/result is shown
output = new JTextArea(10,30);
output.setEditable(false);
output.setFont(new Font("Serif", Font.BOLD, 12));
output.setBackground(Color.WHITE);
outputCenter = BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.BLACK), "Output");
outputCenter.setTitleJustification(TitledBorder.CENTER);
output.setBorder(outputCenter);
c.gridx = 1;
c.gridy = 2;
c.insets = new Insets(50,5,10,10);
c.gridwidth = 3;
container.add(output, c);
//Convert button
convert = new JButton("Convert");
c.gridx = 0;
c.gridy = 3;
c.ipadx = 50;
container.add(convert, c);
}
Output:
Remember, GridBagLayout is a "flexible grid" layout manager. It still relies on the concept of rows and columns, but each row and column has it's own size, based on the requirements of the components and the constraints applied to them.
This means, that you combo box is been aligned to the left position because of a combination of c.anchor = GridBagConstraints.LINE_START and the space requirements of the JTextField sharing the same column.
You "could" change c.anchor = GridBagConstraints.LINE_START to c.anchor = GridBagConstraints.LINE_END, while will (in your case) align the combo box to the right edge of the column, for example...
Another solution would be to use a combination of containers to reduce the overall complexity of the layout. For example, you could add both the combo boxes to their own container, managing the layout requirements for them in an isolated manner and then layout that container within the large scheme of things

GridBag Layout, positioning the pieces

What I want is the label and check box at the top left corner and the three buttons on the bottom right corner.
However, it doesn't appear the the anchors are working properly.
Result:
Code:
JPanel bottomPanel = new JPanel( new GridBagLayout() );
GridBagConstraints c = new GridBagConstraints();
c.gridx = 0;
c.gridy = 0;
c.insets = new Insets(0, 0, 0, 20);
c.anchor = GridBagConstraints.NORTHEAST;
bottomPanel.add(spinachLabel, c);
c = new GridBagConstraints();
c.gridx = 1;
c.gridy = 0;
c.anchor = GridBagConstraints.NORTHEAST;
bottomPanel.add(checkbox, c);
c = new GridBagConstraints();
c.gridx = 0;
c.gridy = 5;
c.weightx = 0.5;
c.insets = new Insets(0, 0, 0, 5);
c.anchor = GridBagConstraints.SOUTHWEST;
bottomPanel.add(applyButton, c);
c = new GridBagConstraints();
c.gridx = 1;
c.gridy = 5;
c.weightx = 0.5;
c.insets = new Insets(0, 0, 0, 5);
c.anchor = GridBagConstraints.SOUTHWEST;
bottomPanel.add(refreshButton, c);
c = new GridBagConstraints();
c.gridx = 2;
c.gridy = 5;
c.weightx = 0.5;
c.anchor = GridBagConstraints.SOUTHWEST;
bottomPanel.add(cancelButton, c);
return bottomPanel;
First, we need to clarify what GridBagConstraints.anchor does: It specifies the placement of a component within the GridBagLayout cell.
spinachLabel is being placed at gridx = 0. applyButton is also being placed at gridx = 0. Therefore, they are guaranteed to be placed in cells which are in the same column. Their respective anchor constraints can move their position within their cells, but cannot move the cells themselves.
Second, you have not set any weighty constraints. Whenever a container which uses a GridBagLayout is larger than the preferred sizes of its child components, it uses the GridBagLayout’s weight constraints to decide which cells will grow to take up that extra space. When there are no weight constraints at all, as is the case for the vertical dimension in your layout, GridBagLayout doesn’t give any of the cells that extra space, and instead centers them. That’s what you’re seeing: Since no cell has a weighty set, all the cells are vertically centered.
In summary, your components will never appear at the top and bottom, unless you set some positive weighty constraints.
This doesn’t seem like a good use of GridBagLayout. When you want to place components at the edges, BorderLayout is usually a better choice:
JCheckBox checkbox = new JCheckBox("Enable Spinach Study");
JButton applyButton = new JBUtton("Apply");
JButton refreshButton = new JBUtton("Refresh");
JButton cancelButton = new JBUtton("Cancel");
JComponent buttonPane = new JPanel(new FlowLayout(FlowLayout.TRAILING));
buttonPane.add(applyButton);
buttonPane.add(refreshButton);
buttonPane.add(cancelButton);
JPanel bottomPanel = new JPanel(new BorderLayout());
bottomPanel.add(checkbox, BorderLayout.PAGE_START);
bottomPanel.add(buttonPane, BorderLayout.PAGE_END);
(A JCheckBox should always have text, rather than being placed to the right of a label. That way, the user has a much larger mouse target, and your user interface is accessibility compatible.)

Choosing a layout manager

I'm trying to set up a couple of labels and textfields in a table-like style.
Currently I'm using the GridLayout, which kind of works as I want it to. However, the TextFields and Button is expanding to the full size of the cell.
How can I make the TextFields and Button "normal" sized, and what Layout Manager would accomplish this the easiest way?
Here's the current code and a screenshot:
JPanel forms = new JPanel();
forms.setLayout(new GridLayout(3, 2));
JLabel lbl_navn = new JLabel("Virksomhedsnavn:");
JTextField txt_navn = new JTextField();
JLabel lbl_adresse = new JLabel("Adresse:");
JTextField txt_adresse = new JTextField();
forms.add(lbl_navn);
forms.add(txt_navn);
forms.add(lbl_adresse);
forms.add(txt_adresse);
forms.add(Box.createRigidArea(new Dimension(10, 10)));
forms.add(new JButton("Opret virksomhed"));
I suggest you use gridBagLayout:
http://docs.oracle.com/javase/tutorial/uiswing/layout/gridbag.html
As an example:
JPanel forms = new JPanel();
forms.setLayout(new GridBagLayout());
JLabel lbl_navn = new JLabel("Virksomhedsnavn:");
JTextField txt_navn = new JTextField();
JLabel lbl_adresse = new JLabel("Adresse:");
JTextField txt_adresse = new JTextField();
//Setting grid bag constraints
GridBagConstraints c = new GridBagConstraints();
// Grid position coordinates
c.gridx = 0; c.gridy = 0;
//Align panel in top-left corner
c.anchor=GridBagConstraints.LINE_START;
forms.add(lbl_navn, c);
c.gridx = 1; c.ipadx = 195;
forms.add(txt_navn, c);
c.gridy = 1; c.gridx = 0; c.ipadx = 0;
forms.add(lbl_adresse, c);
c.gridx = 1; c.ipadx = 195;
forms.add(txt_adresse,c);
c.gridy = 2; c.gridx = 0; c.ipadx = 0;
forms.add(Box.createRigidArea(new Dimension(10, 10)),c);
c.anchor=GridBagConstraints.CENTER;
c.gridy = 2; c.gridx = 1;
forms.add(new JButton("Opret virksomhed"),c);
Hope this helps.
I think you can refer to this question where useful answers have been given:
JTextField Fixed Height
I read good things about Mig layout a while ago, I never used, but seems very powerful.
Check this Mig layout, may be a good solution for your problems.
UPDATE:
Mig layout is not a "standard" layout from sun/oracle.
GridBagLayout as mentioned, can accomplished your objectives(from experience). I personally when I want fixed sizes components I use to work with "null layouts".

How to set gaps for ALL Components in the GridBagLayout?

When you are using group layout you set all the gaps with:
setAutoCreateGaps(true);
setAutoCreateContainerGaps(true);
Is there a same function for GridBagLayout?
In GridBagLayout, using GridBagConstraints you can set gaps with the below properties;
GridBagConstraints.ipadx,GridBagConstraints.ipady:
Specifies the component's internal padding within the layout.
GridBagConstraints.insets:
Specifies the component's external padding.
GridBagConstraints.weightx,GridBagConstraints.weighty:
Used to determine how to distribute space.
For Example:
pane.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.HORIZONTAL;
c.ipady = 40; //make this component tall
c.ipadx = 10; //make this component wide
c.anchor = GridBagConstraints.PAGE_END; //bottom of space
c.insets = new Insets(10,0,0,0); //top padding
c.gridx = 1; //first column
c.gridy = 2; //third row
c.gridwidth = 2; //2 columns wide
c.weightx = 0.5; //increase horizontal space
c.weighty = 1.0; //increase vertical space
Setting Gap Sizes in a GridBadLayout
good description
use EmptyBorders
use invisible JComponents

Categories