Java Swing GridBagLayout Component Positioning - java

I am using Swing's GridBagLayout for the fist time and I have so far only added two components to a container, although I intend to add more below vertically. So far, the first component (a JLabel) is positioned correctly at PAGE_START, and I have remembered to set weight attributes for the components' corresponding GridBagConstraints. The second component (a JTextField) however is not positioning as I intended and it being centered in the container rather than moving up underneath the JLabel. I have attempted to use multiple anchor constants including FIRST_LINE_START, PAGE_START, NORTH & NORTHWEST but so far nothing is working.
And so, once again I call for the gifted coders of stackoverflow for help. Below is a snippet of the code and below that is an image of the problem graphically.
// Instantiate components and configure their corresponding GridBagConstraints attributes
// refPlusType properties
refPlusType = new JLabel("<html><h3>"+"Reference"+" - "+"Job Type"+" </h3><hr /></html>");
refPlusTypeGC = new GridBagConstraints();
refPlusTypeGC.gridx = 0; // Grid position
refPlusTypeGC.gridy = 0;
refPlusTypeGC.gridwidth = 2; // Number of colums occupied by component
refPlusTypeGC.insets = new Insets(5, 10, 5, 10); // Specifies margin
refPlusTypeGC.weightx = 0.1; // Required for anchor to work.
refPlusTypeGC.weighty = 0.1; // Required for anchor to work.
refPlusTypeGC.anchor = GridBagConstraints.PAGE_START; // Position in container
// addressLine1 properties
addressLine1 = new JTextField();
addressLine1GC = new GridBagConstraints();
addressLine1GC.gridx = 0;
addressLine1GC.gridy = 1;
addressLine1GC.gridwidth = 2;
addressLine1GC.insets = new Insets(0, 10, 0, 10);
addressLine1GC.fill = GridBagConstraints.HORIZONTAL; // Specifies component fill Horizontal space
addressLine1GC.weightx = 0.1;
addressLine1GC.weighty = 0.1;
addressLine1GC.anchor = GridBagConstraints.FIRST_LINE_START;
// Add components to this HALLogisticsDetailsPanel
this.add(refPlusType, refPlusTypeGC);
this.add(addressLine1, addressLine1GC);
Image below;
Thank you all for any help you can offer.

Try increasing the weighty for addressLine1 to a much larger value. I did a quick test setting it to 1000:
addressLine1GC.weighty = 1000.0;
and that pushed the addressLine1 field up under the label with the whitespace below.

anchor = NORTH works like a charm:
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class TestJPanels {
private JLabel refPlusType;
private JTextField addressLine1;
protected void initUI() {
final JFrame frame = new JFrame(TestJPanels.class.getSimpleName());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel(new GridBagLayout());
// Instantiate components and configure their corresponding GridBagConstraints attributes
// refPlusType properties
refPlusType = new JLabel("<html><h3>" + "Reference" + " - " + "Job Type" + " </h3><hr /></html>");
GridBagConstraints refPlusTypeGC = new GridBagConstraints();
refPlusTypeGC.gridwidth = GridBagConstraints.REMAINDER; // Number of colums occupied by component
refPlusTypeGC.insets = new Insets(5, 10, 5, 10); // Specifies margin
refPlusTypeGC.weightx = 1; // Required for anchor to work.
refPlusTypeGC.anchor = GridBagConstraints.PAGE_START; // Position in container
// addressLine1 properties
addressLine1 = new JTextField(20);
GridBagConstraints addressLine1GC = new GridBagConstraints();
addressLine1GC.insets = new Insets(0, 10, 0, 10);
addressLine1GC.fill = GridBagConstraints.HORIZONTAL; // Specifies component fill Horizontal space
addressLine1GC.weightx = 1;
addressLine1GC.weighty = 1;
addressLine1GC.anchor = GridBagConstraints.NORTH;
// Add components to this HALLogisticsDetailsPanel
panel.add(refPlusType, refPlusTypeGC);
panel.add(addressLine1, addressLine1GC);
frame.add(panel);
frame.setSize(600, 600);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new TestJPanels().initUI();
}
});
}
}

The best 'tutorial' for GridBagLayout that I have seen was created by Scott Stanchfield. You can find a link to the PowerPoint presentation he gave at JavaOne 2001 here
There used to be an article online with the same information, but it appears to have been swallowed up by Oracle.
Please read all the warnings about why GBL is not ideal. If you are determined to use it, Scott gives a great visual lesson on how to determine all the constraints by creating a simple sketch of your GUI.
Jim S.

Okay, I got it. I don't like accepting my own answers but here we go. At the end of the day I am trying to get the whole lot to bunch together properly at the top of the container. Adding weighty attributes to all the components individually means that the remaining space in the container is distributed between all of them (relative to their weighty attribute) therefore spacing them out.
The answer seems to be that by adding a weighty attribute to the lowest component in the GridBagLayout, the rest of the remaining space is allocated to below the lowest component and therefore pushing all components to the top. By default is seems that when remaining space is allocated to a component based on it's weight, it is allocated below it (at least on the y axis).
Here is the new code with three components to help demonstrate;
// Instantiate components and configure their corresponding GridBagConstraints attributes
// refPlusType properties
refPlusType = new JLabel("<html><h3>"+"Reference"+" - "+"Job Type"+" </h3><hr /></html>");
refPlusTypeGC = new GridBagConstraints();
refPlusTypeGC.gridx = 0; // Grid position
refPlusTypeGC.gridy = 0;
refPlusTypeGC.gridwidth = 2; // Number of colums occupied by component
refPlusTypeGC.insets = new Insets(5, 10, 5, 10); // Specifies margin
// addressLine1 properties
addressLine1 = new JTextField();
addressLine1GC = new GridBagConstraints();
addressLine1GC.gridx = 0;
addressLine1GC.gridy = 1;
addressLine1GC.gridwidth = 2;
addressLine1GC.insets = new Insets(0, 10, 0, 10);
addressLine1GC.fill = GridBagConstraints.HORIZONTAL; // Specifies component fill Horizontal space
// addressLine2 properties
addressLine2 = new JTextField();
addressLine2GC = new GridBagConstraints();
addressLine2GC.gridx = 0;
addressLine2GC.gridy = 2;
addressLine2GC.gridwidth = 2;
addressLine2GC.insets = new Insets(0, 10, 0, 10);
addressLine2GC.fill = GridBagConstraints.HORIZONTAL; // Specifies component fill Horizontal space
addressLine2GC.weighty = 1; // Required for anchor to work.
addressLine2GC.anchor = GridBagConstraints.NORTH; // Position in container
// Add components to this HALLogisticsDetailsPanel
this.add(refPlusType, refPlusTypeGC);
this.add(addressLine1, addressLine1GC);
this.add(addressLine2, addressLine2GC);

Related

GridBagLayout - Trouble placing components without anchor

I'm making an assignment planner program. For the containers (the assignments), I want to place certain components into certain places. However. I can only seem to move components around by using anchor. It seems as if my gridx and gridy do nothing. Could anyone point out my problem and possibly offer some suggestions. My code and a picture of the intended final result are provided below.
Code:
import javax.swing.*;
import java.awt.*;
import static java.awt.GridBagConstraints.*;
//import java.util.ArrayList;
public class MyWindow
{
private final JFrame frame = new JFrame();
private final int WINDOW_WIDTH = 500, WINDOW_DEPTH = 500;
private JPanel panel;
private JPanel toDoList, completed;
private int scrollPaneValue = 110;
//ArrayList<JFrame> frame = new ArrayList<>();
public MyWindow()
{
frame.setTitle("Assignment Planner");
this.contents();
}
private void contents()//make a border above each panel stating "TO-DO" or "COMPLETED"
{//use an arraylist to create containers ArrayList<JPanel> container = new ArrayList<>();
frame.setSize(WINDOW_WIDTH, WINDOW_DEPTH);
panel = new JPanel(new GridLayout(2, 1));
toDoList = new JPanel();
toDoList.setLayout(new /*GridLayout(0,1,5,5)*/BoxLayout(toDoList, BoxLayout.PAGE_AXIS));
toDoList.setPreferredSize(new Dimension(250, 110));
panel.add(toDoList);
completed = new JPanel();
//panelCompleted.setLayout(new GridLayout(0, 1)); //fix like one above
panel.add(completed);
JScrollPane scroll = new JScrollPane(toDoList);
panel.add(scroll); //scroll panes for both panels
JScrollPane scroll2 = new JScrollPane(completed);
panel.add(scroll2);
toDoList.add(Box.createRigidArea(new Dimension(0,1)));
toDoList.add(assignment());
scrollPaneValue += 110; //add these 2 lines of code, beginning after the first two containers to increase jscrollpane
toDoList.setPreferredSize(new Dimension(250, scrollPaneValue));
//toDoList.revalidate(); may not even need
frame.getContentPane().add(panel, BorderLayout.CENTER);//add the panel in the JFrame's content pane in the center
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
JPanel assignment()
{
JPanel container = new JPanel(new GridBagLayout());
container.setMaximumSize(new Dimension(500,100));
GridBagConstraints cDefault = new GridBagConstraints();
cDefault.weightx = 0.5;
cDefault.insets = new Insets(5,5,5,5);
JCheckBox cb;
JLabel dueDate, description;
JButton edit;
cb = new JCheckBox();
GridBagConstraints cCb = new GridBagConstraints();
cCb.weightx = 0.5;
cCb.weighty = 1;
cCb.fill = GridBagConstraints.NONE;//originally none
cCb.gridx = 0;
cCb.gridy = 0;
//cCb.gridwidth = 1;
//cCb.gridheight = 1;
cCb.anchor = FIRST_LINE_START;//may not need, plus needs static import
cCb.insets = cDefault.insets;
cb.setBackground(Color.RED);
container.add(cb, cCb);
dueDate = new JLabel("Due Date");
GridBagConstraints cDueDate = new GridBagConstraints();
cDueDate.gridx = 1;
cDueDate.gridy = 0;
cDueDate.gridwidth = 2;
//cDueDate.fill = GridBagConstraints.HORIZONTAL;
cDueDate.anchor = PAGE_START;
dueDate.setBackground(Color.BLUE);
//cDueDate.anchor = FIRST_LINE_START;
container.add(dueDate, cDueDate);
edit = new JButton("Edit");
GridBagConstraints e = new GridBagConstraints();
e.gridx = 4;
e.gridy = 0;
e.anchor = GridBagConstraints.FIRST_LINE_END;
e.insets = cDefault.insets;
edit.setBackground(Color.GREEN);
container.add(edit, e);
description = new JLabel("Description...");
GridBagConstraints d = new GridBagConstraints();
d.gridx = 1;
d.gridy = 3;
d.gridwidth = 3;
d.fill = GridBagConstraints.HORIZONTAL;
description.setBackground(Color.YELLOW);
container.add(description, d);
container.setBackground(Color.LIGHT_GRAY);//does no fill area behind checkbox
return container;
}
}
What I want the container to look like:
This just concerns my lack of knowledge with GridBagLayout.
Start with the section from the Swing tutorial on How to Use GridBagLayout for working examples and an explanation of all the constraints.
A few things about the code:
//container.setMaximumSize(new Dimension(500,100));
Don't set a maximum size. The layout manager will determine the size of the panel.
//cCb.weightx = 0.5;
//cCb.weighty = 1;
The above code assigns all the extra space of the panel to the check box, since it is the only component with a weightx/y constraint. I doubt you want that. Try commenting out those statements to see what happens.
dueDate.setOpaque(true);
dueDate.setBackground(Color.BLUE);
Yes, that is a good idea to set a background to see the actual size of the component. Problem is a JLabel is transparent by default so the background is never painted. You need need to make your labels opaque if you want to see the background. Another approach to help with debugging is to add LineBorder to the label, then you don't need to worry about transparency.
//e.gridx = 4;
e.gridx = 3;
Be careful with the grid value. You can't just use an value. The first component has a width of 1 and the second a width of 2, so the this component should start at 3.
I can only seem to move components around by using anchor
Actually, I don't this the anchor is doing anything. As I understand it, the anchor only has meaning when the component size is smaller than the grid size. In your original code, only the check box used weightx/y values, so that is the only component where this is true.
The GridBagLayout is one of the most complicated (and flexible) layout manager to use, so yes it takes practice to learn how to use it. Reread the tutorial and play with the constraints.

What settings should I use to resolve this GridBagLayout resizing issue?

I have been searching and trying ways to resolve the problems I encountered with GridBagLayout resizing but to no avail. The problems are:
I drag the bottom of the JDialog window down to make it taller; the search panel (above panel in the below screenshot) kept getting taller, just adding white space that it didn't need for its contents (I don't want this wasted space which takes height away from the scrolling table below it).
If I move the right side of the window to make it a bit narrower, the scroll panel becomes too short even though my screen and the window could have displayed its full height; a vertical scroll bar appears (I don't like the panels to scroll vertically, just horizontally.)
My JDialog that holds below components in the upper right portion uses below layout manager and constraints:
JPanel level 1 uses GridBagLayout Setting 1 (see below)
JScrollPane level 2 uses GridBagLayout Setting 1
JPanel level 3 uses GridBagLayout Setting 2
JPanel level 4 uses GridBagLayout Setting 2
JPanel level 5 uses GridBagLayout Setting 2
JPanel level 5 uses GridBagLayout Setting 2
GridBagLayout.GridBagConstraints (c)
Setting 1:
c.fill = GridBagConstraints.BOTH;
c.weightx = 99.0;
c.weighty = 99.0;
Setting 2:
c.fill = GridBagConstraints.NONE;
c.weightx = 1.0;
c.weighty = 1.0;
Originally, this is my JDialog if I don't use JScrollPane:
If I drag the window to make it bigger, the size of the JPanel (which was what I use before I used JScrollPane to make it scrollable horizontally) remains as it is. I want to achieve the same behavior, only that I want to make it horizontally scrollable.
What layout manager should I use to resolve this resizing problem? If I have to really use GridBagLayout, what constraints/settings should I use? I would highly appreciate any suggestion. Thank you!
UPDATE 1 ------------------------------------------------------
Kindly check sample code scenario below. Both scrollable panels (RED and BLUE) use GridBagConstraints.BOTH, weightx and weighty equal to 99.0. I want the red panel to have a height that is enough to contain the text field. I also want that when the dialog is dragged down to make the window bigger, the red panel's height remains the same. Please note that in the actual screen, both panels' number of contents may change (add/minus buttons exist), hence, setting of minimum panel size (for resizing) won't help. Kindly advise how I should go about this case. Thanks!
package cfr.view.search;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.border.EmptyBorder;
public class GBLSample extends JDialog {
private JPanel contentPane;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
GBLSample frame = new GBLSample();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public GBLSample() {
setBounds(100, 100, 350, 400);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
GridBagLayout gbl_contentPane = new GridBagLayout();
contentPane.setLayout(gbl_contentPane);
// RED PANEL ------------------------------------------------
JScrollPane sp1 = new JScrollPane();
GridBagConstraints gbc1 = new GridBagConstraints();
gbc1.fill = GridBagConstraints.BOTH;
gbc1.weightx = 99.0;
gbc1.weighty = 99.0;
contentPane.add(sp1, gbc1);
JPanel redPanel = new JPanel();
redPanel.setBackground(Color.RED);
JTextField field = new JTextField(20);
GridBagConstraints gbc2 = new GridBagConstraints();
gbc2.anchor = GridBagConstraints.PAGE_START;
gbc2.fill = GridBagConstraints.NONE;
contentPane.add(field, gbc2);
redPanel.add(field);
sp1.setViewportView(redPanel);
// BLUE PANEL ------------------------------------------------
JScrollPane sp2 = new JScrollPane();
GridBagConstraints gbc3 = new GridBagConstraints();
gbc3.fill = GridBagConstraints.BOTH;
gbc3.gridx = 0;
gbc3.gridy = 1;
gbc3.weightx = 99.0;
gbc3.weighty = 99.0;
contentPane.add(sp2, gbc3);
JPanel bluePanel = new JPanel();
bluePanel.setBackground(Color.BLUE);
sp2.setViewportView(bluePanel);
}
}
UPDATE 2 ------------------------------------------------------
Still have the same problem with the JPanel's sizing as #1 above.
Problem 1
try this code:
package test;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.border.EmptyBorder;
public class GridBagLayoutSample extends JFrame {
private JPanel contentPane;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
GridBagLayoutSample frame = new GridBagLayoutSample();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public GridBagLayoutSample() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
GridBagLayout gbl_contentPane = new GridBagLayout();
gbl_contentPane.columnWidths = new int[]{0, 0};
gbl_contentPane.rowHeights = new int[]{50, 0, 0};
//the 1.0 value in columnWeights let redPanel and scrollPane (that contain bleuPanel) grow horizontally
//the 1.0 value is in the first index so it affect the first column
//you still need to use a valid value for gbc_redPanel.fill and gbc_scrollPane.fill;
gbl_contentPane.columnWeights = new double[]{1.0, Double.MIN_VALUE};
//the 0.0 value of rowWeights => components in first row will not grow
//the 0.0 value of rowWeights => components in second row will grow
gbl_contentPane.rowWeights = new double[]{0.0, 1.0, Double.MIN_VALUE};
contentPane.setLayout(gbl_contentPane);
JPanel redPanel = new JPanel();
redPanel.setBackground(Color.RED);
GridBagConstraints gbc_redPanel = new GridBagConstraints();
gbc_redPanel.insets = new Insets(0, 0, 5, 0);
gbc_redPanel.fill = GridBagConstraints.BOTH;
gbc_redPanel.gridx = 0;
gbc_redPanel.gridy = 0;
contentPane.add(redPanel, gbc_redPanel);
JScrollPane scrollPane = new JScrollPane();
GridBagConstraints gbc_scrollPane = new GridBagConstraints();
gbc_scrollPane.fill = GridBagConstraints.BOTH;
gbc_scrollPane.gridx = 0;
gbc_scrollPane.gridy = 1;
contentPane.add(scrollPane, gbc_scrollPane);
JPanel bleuPanel = new JPanel();
bleuPanel.setBackground(Color.BLUE);
//scrollpane work with the preferred size of the component in the viewportView
//try to change this values
bleuPanel.setPreferredSize(new Dimension(400, 400));
scrollPane.setViewportView(bleuPanel);
}
}
add this to your code
gbl_contentPane.rowHeights = new int[]{40, 0, 0};
gbl_contentPane.rowWeights = new double[]{0.0,0.0, 1.0, Double.MIN_VALUE};
gbc1.gridx = 0;
gbc1.gridy = 0;
and remove this
gbc1.weightx = 99.0;
gbc1.weighty = 99.0;
Maybe a GridBagLayout might not be suited for your current UI, and a BorderLayout would work better? Put the red panel in BorderLayout.NORTH and put the blue panel in BorderLayout.CENTER. Components in the CENTER region will grow and shrink as you resize your dialog, and your red panel's preferredSize will be respected as you +/- items.
I have been searching and trying ways to resolve the problems I encountered with GridBagLayout resizing but to no avail.
Welcome to GridBagLayout.
First thing to note is that in
JPanel redPanel = new JPanel();
redPanel.setBackground(Color.RED);
JTextField field = new JTextField(20);
// GridBagConstraints gbc2 = new GridBagConstraints();
// gbc2.anchor = GridBagConstraints.PAGE_START;
// gbc2.fill = GridBagConstraints.NONE;
// contentPane.add(field, gbc2);
redPanel.add(field);
sp1.setViewportView(redPanel);
You are adding the text field to the content pane and then adding it again to the panel, which overrides your previous assignment (a component can only belong to one container). I commented out the lines which do nothing. The choice for how to lay out the text field in the red panel is completely different than the choice of how to lay out the red panel in the content pane.
I want the red panel to have a height that is enough to contain the text field.
That is taken care of by the layout manager. However, if you resize the window manually so that the panel will not have enough space, then scrollbars will appear provided that the panel is in a JScrollPane. You can try to #Override the getMinimumSize of the panel to its getPreferredSize, but not all layout managers respect it, I believe.
Regardless, I don't see why you need the scroll pane for the red panel at all.
I also want that when the dialog is dragged down to make the window bigger, the red panel's height remains the same.
Then you should set its weighty to 0.
Note: don't use underscores (_) in non-final variable names in accordance with the Java naming conventions (gbl_contentPane should be gblContentPane).
Edit
Here is an example of of dynamically changing the allocated size for the redPanel. I use BorderLayout for the content pane (also suggested by Dan O) for simplicity.
public class GBLSample extends JDialog {
private JPanel contentPane;
private JScrollPane redSP = new JScrollPane(new RedPanel());
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
GBLSample frame = new GBLSample();
frame.setVisible(true);
});
}
private class RedPanel extends JPanel {
RedPanel() {
setLayout(new GridBagLayout());
setBackground(Color.RED);
GridBagConstraints c = new GridBagConstraints();
c.anchor = GridBagConstraints.FIRST_LINE_START;
add(new JTextField(10), c);
c.weightx = 1;
c.gridx = 1;
add(new JComboBox<>(), c);
c.weightx = 0;
c.gridx = 0;
add(new JComboBox<>(), c);
c.gridx = 1;
add(new JComboBox<>(), c);
c.weighty = 1;
c.gridx = 0;
c.gridy = 2;
add(new JButton("SSSS"), c);
}
#Override
public Dimension getPreferredSize() {
Dimension dim = super.getPreferredSize();
JScrollBar sb = redSP.getHorizontalScrollBar();
if (!sb.isShowing())
return dim;
return new Dimension(dim.width, dim.height + sb.getHeight());
}
}
public GBLSample() {
setBounds(100, 100, 350, 400);
contentPane = new JPanel(new BorderLayout());
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
// RED PANEL ------------------------------------------------
redSP.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
contentPane.add(redSP, BorderLayout.PAGE_START);
// BLUE PANEL ------------------------------------------------
JPanel bluePanel = new JPanel();
bluePanel.setBackground(Color.BLUE);
contentPane.add(new JScrollPane(bluePanel));
}
}
The idea is to add all extra space at the bottom of the panel by giving all the weight to a component on the bottom (and similarly can be done for the x axis with a right-most component). When the scrollbar is shown, the panel recalculates its height and adds the scrollbar's height to to itself (to the bottom most component), then the scrollbar does not hide anything.
Unfortunately, there was a bug in the system's overridden JPanel.getMinimumSize() that was causing my search panel to get squished out of existence. I was able to find a fix for it already without changing any setting with the system's customized layout manager. Still, thanks a lot for all your answers and help.

Grid Bag Layout doesnt recognize my commands?

Im making an application that uses a lot of constructors, and I understood that you cant use the Drag and Drop tool of netbeans for making a constructor, and i thought it was good idea to learn how to code fully organized windows, anyways I read a DEITEL Java book that uses a method for adding objects to the container, here it is:
private void addobject(Component componente, int column, int row, int width
int height){
//C will be the GridBagConstraints
//And I made a new GridBagLayout called "v"
//My Panel or container is called objcontainer and the LayoutManager is v
c.gridx = column;
c.gridy = row;
c.gridwidth = width;
c.gridheight = height;
v.setConstraints(componente, c);
objcontainer.add(componente);
}
The method is declared in the same class in where the constructor is, it worked separating only by one gridy. But when I put it 2 or more away that the last object it just stays like if I put 1.
I dont know if thats how it works, also the anchors dont work perfectly, besides the LINE START one, the Center ones are failing.
Here is the code, anyways thanks:
package Windows;
import java.awt.*;
import javax.swing.*;
public class agregaringreso extends JDialog{
private int ingreso;
private String nombreingreso;
private String Frecuencia [] = {"Solo una vez", "Cada semana","Cada 2 semanas", "Cada 3 semanas", "Cada mes,"};
Container contenedor;
JPanel objcontainer;
GridBagLayout esquema;
GridBagConstraints c;
JButton aceptar;
JLabel title;
JLabel ingreso2;
JLabel nombreingreso2;
JLabel frecuencia2;
JTextField ingreso3;
JTextField nombreingreso3;
JComboBox frecuencia3;
private void addobjeto(Component componente, int columna, int fila, int ancho, int alto){
c.gridx = columna;
c.gridy = fila;
c.gridwidth = ancho;
c.gridheight = alto;
esquema.setConstraints(componente, c);
objcontainer.add(componente);
}
public agregaringreso(){
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
setTitle("Agregar Nuevo Ingreso - EkPek");
pack();
setResizable(false);
setSize(500, 200);
setLocationRelativeTo(null);
//FASE DE INICIALIZACION
contenedor = getContentPane();
objcontainer = new JPanel();
esquema = new GridBagLayout();
c = new GridBagConstraints();
aceptar = new JButton("Aceptar");
title = new JLabel("Agregar Nuevo Ingreso");
ingreso2 = new JLabel("Monto del Ingreso: ");
nombreingreso2 = new JLabel("Nombre del Ingreso: ");
frecuencia2 = new JLabel("Frecuencia con la cual recibe el ingreso: ");
ingreso3 = new JTextField("Escriba aqui el monto");
nombreingreso3 = new JTextField("Escriba aqui el nombre");
frecuencia3 = new JComboBox(Frecuencia);
//FASE DE ACOMODO
c.anchor = GridBagConstraints.CENTER;
addobjeto(title, 0, 0, 1, 1);
c.anchor = GridBagConstraints.LINE_START;
addobjeto(nombreingreso2 , 0, 4, 1, 1);
addobjeto(nombreingreso3, 1, 4, 1, 1);
addobjeto(ingreso2, 0, 5, 1, 1);
addobjeto(ingreso3, 1, 5, 1, 1 );
addobjeto(frecuencia2, 0 , 6, 1, 1);
addobjeto(frecuencia3, 1, 6, 1, 1);
c.anchor = GridBagConstraints.CENTER;
addobjeto(aceptar,0 ,7 ,1, 1);
contenedor.add(objcontainer);
objcontainer.setLayout(esquema);
setVisible(true);
}
}
The order in which you do things is very important. It pointless doing something like...
objcontainer = new JPanel();
esquema = new GridBagLayout();
// Add a bunch of stuff
objcontainer.setLayout(esquema);
You've basically added components to a container (which is using a FlowLayout) and then changed the layout manager. The constraints won't carry across, they are typically incompatiable between layouts (what's a FlowLayout going to do with GridBagConstraints anyway)
Instead, set the layout first
objcontainer = new JPanel();
esquema = new GridBagLayout();
objcontainer.setLayout(esquema);
// Add components.
This also holds true for when you establish a window...
public agregaringreso(){
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
setTitle("Agregar Nuevo Ingreso - EkPek");
pack();
setResizable(false);
setSize(500, 200);
setLocationRelativeTo(null);
It's all kind of pointless, as you've not actually added anything to the window, so pack can't actually do it's job (it's got nothing to pack)
Instead, build the UI first, the "set up" the window properties...
public agregaringreso(){
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
setTitle("Agregar Nuevo Ingreso - EkPek");
//FASE DE INICIALIZACION
contenedor = getContentPane();
contenedor.setBackground(Color.RED);
objcontainer = new JPanel();
esquema = new GridBagLayout();
objcontainer.setLayout(esquema);
c = new GridBagConstraints();
// Add components
setResizable(false);
pack();
setLocationRelativeTo(null);
setVisible(true);
}
it worked separating only by one gridy. But when I put it 2 or more away that the last object it just stays like if I put 1.
If you mean that jumping the value of gridy doesn't do anything than you're right, it's intended. The grid only consists of rows and columns which have components in them.
Example: if you have 2 components, the first at (0,0) and the second at (0,4), then the gridy values 1 through 3 are not counted. The result is that the second component is actually at (0,1). Same goes for gridx.
also the anchors dont work perfectly, besides the LINE START one, the Center ones are failing.
In your example the CENTER anchor value is functioning as intended. If the component is smaller than its available space (and it was not instructed to fill that space with fill), it will be aligned to the center of the space.
What you probably want it for the component to be in the center of the whole grid, and not in the center of its available space. To do this, you must set it so that the component spans the grid's width (or height) by setting its gridwidth appropriately.
Picture comparison
#MadProgrammer's answer already explained how to fix your setup (I will mention it below in the notes). You're supposed to get the top picture after those corrections. The red lines separate rows and the blue lines separate columns - this is your grid.
You see that the components in the first and last rows are centered in column 0 because this is their available space. In the bottom picture, they are centered in both columns since I instructed them to span 2 columns.
I also noted a space discrepancy in the top picture with a yellow rectangle. This happens because the components are not filling all their available space. While it's your choice, it is customary in such layout to do as shown in the bottom picture.
Code comparison
c.anchor = GridBagConstraints.CENTER; // Redundant - default
addobjeto(title, 0, 0, 2, 1);
c.anchor = GridBagConstraints.LINE_START;
c.fill = GridBagConstraints.HORIZONTAL;
addobjeto(nombreingreso2, 0, 1, 1, 1);
addobjeto(nombreingreso3, 1, 1, 1, 1);
addobjeto(ingreso2, 0, 2, 1, 1);
addobjeto(ingreso3, 1, 2, 1, 1);
addobjeto(frecuencia2, 0, 3, 1, 1);
addobjeto(frecuencia3, 1, 3, 1, 1);
c.anchor = GridBagConstraints.CENTER;
c.fill = GridBagConstraints.NONE;
addobjeto(aceptar, 0, 4, 2, 1);
Set the gridwidth of title and aceptar to 2 (GridBagConstraints.REMAINDER will also work) to allow them to span 2 columns.
For the rest of the components, set c.fill = GridBagConstraints.HORIZONTAL; to allow them to align nicely with themselves (yellow rectangle). Remember to reset it c.fill = GridBagConstraints.NONE; for aceptar if you don't want the button to strech.
Specifying c.anchor = GridBagConstraints.CENTER; is redundant for the first component as it is the default, but it can make the code clearer.
Notes:
You don't need your JLabels to be fields as you probably don't need to hold a reference to them. Local variables will do just as well and will decrease the memory usage.
Class names should start with an uppercase (Agregaringreso).
As for my "setup" (as MadProgrammer explained): before adding the components I have
esquema = new GridBagLayout();
objcontainer = new JPanel(esquema);
c = new GridBagConstraints();
and at the end I have
getContentPane().add(objcontainer);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
setTitle("Agregar Nuevo Ingreso - EkPek");
pack();
setResizable(false);
setLocationRelativeTo(null);
setVisible(true);
(You don't need to hold a reference to the content pane.)

How to set JButton size with GridBagLayout

I want to set the size of my JButtons that are at the center of my screen to become larger but I can't seem to find how to do that using GridBagLayouts.
Here is how it looks like :
Here is my code :
// Client
c.fill = GridBagConstraints.BOTH;
c.anchor = GridBagConstraints.CENTER;
c.gridy = 5;
c.gridx = 5;
c.gridwidth = 1;
c.gridheight = 1;
c.insets = new Insets(10, 1, 1, 10);
p.add(b[0], c);
// Server
c.fill = GridBagConstraints.BOTH;
c.anchor = GridBagConstraints.CENTER;
c.gridy = 10;
c.gridx = 5;
c.gridwidth = 1;
c.gridheight = 1;
c.insets = new Insets(10, 1, 1, 10);
p.add(b[1], c);
I want the buttons to take up a larger portion of the empty space around them.
More information was added: Buttons have 50% of the width and [about] 20% of the height of parent [together 50% height including the space in between]. (Slightly rewritten to match the suggestion.)
Solution
Combination of simple Layouts Layouts. Although if you do it like this you will have 3 columns or 3 rows which can't be joined, the rest can easily be changed later:
// row variation
JPanel parent = new JPanel();
parent.setLayout(new GridLayout(3, 1));
parent.add(new JPanel()); // placeholder for 1st row
JPanel row = new JPanel(); // 2nd row
row.setLayout(new GridLayout(1, 3)); // create 3 cells of equal size
row.add(new JPanel()); // 2nd row, 1st cell placeholder
// now you have a 33% x 33% (oops) rectangle in the middle
JPanel controls = new JPanel();
controls.setLayout(new GridLayout(2, 1, 10, 10));
controls.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10);
controls.add(new JButton("Client"));
controls.add(new JButton("Server"));
row.add(controls); // add 2nd row, 2nd cell
row.add(new JPanel()); // 2nd row, 3rd cell placeholder
parent.add(row); // add 2nd row
parent.add(new JPanel()); // placeholder for 3rd row
Easy, but you won't be able to join the cells later:
JPanel parent = new JPanel();
parent.setLayout(newGridLayout(9, 9));
Bottom line: combine different layout managers, put your 2 buttons inside a panel and put some placeholders inside, then it should also work fine with GridBagLayout. That said, I would try to stay flexible by writing reusable components which can easily be combined with any layout manager. Then you don't have to use placeholders superfluous code in order to display the components correctly.
Old Answer
Alternative Solution: Use BoxLayout
BoxLayout is more intuitive and easier to understand when looking at code (of course this is only an opinion).
Decide how your window is structered (is it more like big horizontal components on top of each other PAGE_AXIS or big vertical components next to each other LINE_AXIS) and use this as the outer BoxLayout:
JPanel content = new JPanel(); // or frame
content.setLayout(new BoxLayout(content, BoxLayout.LINE_AXIS));
Add the components along the axis, where you have more than one component along the other axis use a 2nd BoxLayout. You can space components by creating rigid areas (empty rectangles always having the same size) or by adding glue (expanding like gum together with the components).
content.add(BoxLayout.createHorizntalGlue());
JPanel col = new JPanel();
col.setLayout(new BoxLayout(col, BoxLayout.PAGE_AXIS));
JButton clientBtn = new JButton("Client");
JButton serverBtn = new JButton("Server");
col.add(BoxLayout.createVerticalGlue());
col.add(clientBtn);
col.add(BoxLayout.createRigidArea(new Dimension(1, 10)));
col.add(serverBtn);
col.add(BoxLayout.createVerticalGlue());
content.add(col);
content.add(BoxLayout.createHorizontalGlue());
I can't imagine what do you want, but if you want your button to fill around, you can add
c.weightx = ...; //Specifies how to distribute extra horizontal space.
or c.weighty = ...; //Specifies how to distribute extra vertical space.
button.setMargin( new Insets(50, 50, 50, 50) );
This will add extra space to the button and allow the layout managers to do their job based on the preferred size of the button.

How to use GridBagConstraints to create the layout?

I want to layout my JPane like so:
-------
| |
| |
| |
-------
| |
-------
This way, the top section is bigger/taller than the bottom section (the top section consists of another JPanel and uses the Graphics object to display an image, while the bottom section also consists of another JPanel but uses the Graphics object to draw some lines and text).
I've heard that the best way to do this was using the GridBagLayout and GridBagConstraints.
I'm trying to figure out the appropriate properties for the GridBagConstraints, and I'm having some difficulties. This is what I have so far...
For the top part, I have:
gridx = 0
gridy = 0
weighty = 1.0; // expand downwards, because the bottom should never expand in the Y direction
fill = GridBagConstraints.BOTH
For the bottom part, I have:
gridx = 0
gridy = 1
fill = GridBagConstraints.HORIZONTAL
anchor = GridBagConstraints.PAGE_END
Unfortunately, all the ends up happening is a large gray rectangle appears (I have a white background for the application) - no images load, no lines/text appear.
What should I do? What should I adjust?
I've read a few tutorials, but it just seems really confusing, I got it working in my first application, but now when I try to do this it just doesn't seem to work for me.
In general, for gridbag layout
if you want a component scale, you must give its scale direction a weight, and any sizes (width/height) you set for that direction will be ignored by the layout manager.
If you don't want a component scale, the component must have its size defined (if you want, you can dig into this topic in documents of java). In your case of the bottom panel, you need to give its, at least, a preferred height.
This can work as your expectation
pnlTop.setBackground(Color.WHITE);
pnlBottom.setBackground(Color.BLUE);
// Because you don't want the bottom panel scale, you need to give it a height.
// Because you want the bottom panel scale x, you can give it any width as the
// layout manager will ignore it.
pnlBottom.setPreferredSize(new Dimension(1, 20));
getContentPane().setLayout(new GridBagLayout());
GridBagConstraints cst = new GridBagConstraints();
cst.fill = GridBagConstraints.BOTH;
cst.gridx = 0;
cst.gridy = 0;
cst.weightx = 1.0; // --> You miss this for the top panel
cst.weighty = 1.0;
getContentPane().add(pnlTop, cst);
cst = new GridBagConstraints();
cst.fill = GridBagConstraints.HORIZONTAL;
cst.gridx = 0;
cst.gridy = 1;
cst.weightx = 1.0; // You miss this for the bottom panel
cst.weighty = 0.0;
getContentPane().add(pnlBottom, cst);
Further more, if you want to use gridbag layout, I recommend you to try the painless-gridbag library http://code.google.com/p/painless-gridbag/ (I'm the author of that library). It doesn't solve this problem for you (as your problem concerns managing component's size in gridbag layout) but it will save you a lot of typing and make your code easier to maintain
pnlBottom.setPreferredSize(new Dimension(1, 20));
PainlessGridBag gbl = new PainlessGridBag(getContentPane(), false);
gbl.row().cell(pnlTop).fillXY();
gbl.row().cell(pnlBottom).fillX();
gbl.done();
not sure from your question, maybe will help you Top at 70%, Bottom at 30%
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
public class BorderPanels extends JFrame {
private static final long serialVersionUID = 1L;
public BorderPanels() {
getContentPane().setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
JPanel panel1 = new JPanel();
Border eBorder = BorderFactory.createEtchedBorder();
panel1.setBorder(BorderFactory.createTitledBorder(eBorder, "70pct"));
gbc.gridx = gbc.gridy = 0;
gbc.gridwidth = gbc.gridheight = 1;
gbc.fill = GridBagConstraints.BOTH;
gbc.anchor = GridBagConstraints.NORTHWEST;
gbc.weightx = gbc.weighty = 70;
getContentPane().add(panel1, gbc);
JPanel panel2 = new JPanel();
panel2.setBorder(BorderFactory.createTitledBorder(eBorder, "30pct"));
gbc.gridy = 1;
gbc.weightx = 30;
gbc.weighty = 30;
gbc.insets = new Insets(2, 2, 2, 2);
getContentPane().add(panel2, gbc);
pack();
}
public static void main(String[] args) {
new BorderPanels().setVisible(true);
}
}
If you may use 3th party libs, you may consider the FormLayout as well. It allows you to specify the height of each row, and the resize behavior.
I did not test this but
FormLayout layout = new FormLayout(
"pref", //columns
"50dlu:grow(0.2)","25dlu:grow(0.1)" //rows
);
might do the trick. More information on the syntax can be found in the JGoodies Forms pdf

Categories

Resources