This post originated from an RSS feed registered with Java Buzz
by Simon Brown.
Original Post: Source code for GridBagPanel
Feed Title: Simon Brown's weblog
Feed URL: http://www.simongbrown.com/blog/feed.xml?flavor=rss20&category=java
Feed Description: My thoughts on Java, software development and technology.
A little while ago I posted a blog entry about a component that I wrote to help me develop Swing forms. GridBagPanel is an extension of JPanel and after creating an instance of it, you can call the addRow method to add a row containing a label and component such as a textfield. Now that Sam is doing some stuff with Swing, it's reminded me that I never did post the code!
The following code has been pulled out of an existing "framework" but it does function standalone. First of all is an interface called LookAndFeelGuidelines upon which a number of constants are defined.
package swing;
/**
* The Java Look and Feel Design Guidelines
* has recommendations for user interface designs.
*
* This interface is really just a single place to keep constants representing
* the various values for button spacing, component spacing, margins, borders, etc.
*
* Implementing this interface is just an easy way to reference the constants
* defined in this class!
*
* @author Simon Brown
*/
public interface LookAndFeelGuidelines {
...
/** the horizontal spacing between components in a form */
public final static int HORIZONTAL_COMPONENT_SPACING = 5;
/** the vertical spacing between components (and rows of components) in a form */
public final static int VERTICAL_COMPONENT_SPACING = 5;
/** the horizontal spacing between a label and the component it is associated with */
public final static int LABEL_COMPONENT_SPACING = 12;
}
Most of this can be ignored to be honest so I've omitted it here, but essentially these are constants taken from the first edition of the Java Look and Feel Guidelines from a few years ago. Next up is the code for GridBagPanel itself.
package swing;
import javax.swing.*;
import java.awt.*;
/**
* An extension of JPanel with it's layout already set to GridBagLayout.
*
* This has been created to take the "pain" out of creating professional
* looking user interfaces using the GridBagLayout, which also conform
* to the recommendations made in the Java Look and Feel Design Guidelines.
*
* @author Simon Brown
*/
public class GridBagPanel extends JPanel implements LookAndFeelGuidelines {
/** the grid bag constraints used internally within this panel */
private GridBagConstraints constraints;
/** the grid bag layout used internally within this panel */
private GridBagLayout layout;
/** a counter used to keep track of the current "grid x" position when adding components */
private int gridx = 0;
/** a counter used to keep track of the current "grid y" position when adding components */
private int gridy = 0;
/** the number of "rows" that the grid bag layout consists of */
private int rows = 1;
/** the number of "columns" that the grid bag layout consists of */
private int columns = 2;
/**
* Constructor for this panel, allowing the number of rows and columns
* in the underlying grid bag layout to be specified.
*
* @param rows the number of rows in the layout
* @param columns the number of columns in the layout
*/
public GridBagPanel(int rows, int columns) {
this.rows = rows;
this.columns = columns;
init();
initUI();
initListeners();
}
/**
* Sets up the layout and constraints for this panel.
*/
private void init() {
constraints = new GridBagConstraints();
constraints.fill = GridBagConstraints.BOTH;
constraints.anchor = GridBagConstraints.NORTH;
layout = new GridBagLayout();
setLayout(layout);
}
/**
* Placeholder for any code to set up the user interface - override this!
*/
protected void initUI() {
}
/**
* Placeholder for any code to set up the listeners - override this!
*/
protected void initListeners() {
}
/**
* Groups of components in a form should be separated by "extra" space
* between the rows - this method allows that space to be inserted.
*/
public void addSeparator() {
JLabel label = new JLabel();
constraints.gridx = 0;
constraints.gridy = gridy++;
constraints.weightx = 1;
constraints.gridwidth = columns;
constraints.gridheight = 1;
constraints.insets = new Insets(0, 0, 6, 0);
add(label, constraints);
}
/**
* A convenient way of adding a label and component pair to the grid bag
* layout, conforming to the Java Look and Feel Design Guidelines.
*
* For any grid baggers out there, the label will be zero weighted whilst
* the component will be given a weight of 1 to allow it to grow horizontally.
*
* @param labelText the text for the label to be associated with
* "component"
* @param component the JComponent (e.g. textfield, combo, ...) to
* be added
*/
public JLabel addRow(String labelText, JComponent component) {
JLabel label = addLabel(labelText);
addToEndOfRow(component, true, false);
return label;
}
/**
* A convenient way of adding a label and component pair to the grid bag
* layout, conforming to the Java Look and Feel Design Guidelines.
*
* For any grid baggers out there, the label will be zero weighted whilst
* the component will be given a weight of 1 to allow it to grow horizontally.
*
* @param labelText the text for the label to be associated with
* "component"
* @param component the JComponent (e.g. textfield, combo, ...) to
* be added
* @param mnemonic the single character mnemonic to be diaplayed on
* the label to allow the user to jump straight to
* component with a keystroke
*/
public JLabel addRow(String labelText, JComponent component, char mnemonic) {
JLabel label = addLabel(labelText);
label.setLabelFor(component);
label.setDisplayedMnemonic(mnemonic);
addToEndOfRow(component, true, false);
return label;
}
/**
* Adds a label to the current row in the layout. This is used by the addRow
* methods, but can also be called to add a single label if necessary.
*
* @param labelText the text for the label to be added
*/
public JLabel addLabel(String labelText) {
JLabel label;
if (labelText.length() > 0) {
label = new JLabel(labelText + ":", SwingConstants.LEFT);
} else {
label = new JLabel("", SwingConstants.LEFT);
}
label.setVerticalAlignment(SwingConstants.TOP)
8
;
19cd
if ((gridy + 1) == rows) {
constraints.insets = new Insets(0, 0, 0, LABEL_COMPONENT_SPACING - HORIZONTAL_COMPONENT_SPACING);
} else {
constraints.insets = new Insets(0, 0, VERTICAL_COMPONENT_SPACING, LABEL_COMPONENT_SPACING - HORIZONTAL_COMPONENT_SPACING);
}
constraints.gridx = gridx++;
constraints.gridy = gridy;
// if we've reached the end of the row (e.g. gridx is now 2 in a 2 column grid)
// - reset gridx back to 0
// - increment gridy (representing the next row)
if (gridx == columns) {
gridx = 0;
gridy++;
}
constraints.weightx = 0;
constraints.weighty = 0;
constraints.gridwidth = 1;
constraints.gridheight = 1;
add(label, constraints);
return label;
}
/**
* Adds a component to the end of the current row - specifying whether it
* should be remain the same size or be expandable with the container
* it is in.
*
* @param component the JComponent to be added to the end of the
* current row
* @param horizontallyExpandable true if the component should expand horizontally
* with the surrounding container, false otherwise
* @param verticallyExpandable true if the component should expand vertically
* with the surrounding container, false otherwise
*/
public void addToEndOfRow(JComponent component, boolean horizontallyExpandable, boolean verticallyExpandable) {
constraints.gridx = gridx;
constraints.gridy = gridy;
int leftInsets;
int bottomInsets;
if ((gridy + 1) == rows) {
bottomInsets = 0;
} else {
bottomInsets = VERTICAL_COMPONENT_SPACING;
}
if (gridx == 0) {
leftInsets = 0;
} else {
leftInsets = HORIZONTAL_COMPONENT_SPACING;
}
constraints.insets = new Insets(0, leftInsets, bottomInsets, 0);
constraints.gridwidth = columns - gridx;
constraints.gridheight = 1;
if (horizontallyExpandable) {
constraints.weightx = 1;
} else {
constraints.weightx = 0;
}
if (verticallyExpandable) {
constraints.weighty = 1;
} else {
constraints.weighty = 0;
}
// - reset gridx back to 0
// - increment gridy (representing the next row)
gridx = 0;
gridy++;
add(component, constraints);
}
/**
* Adds a component to the current row - specifying whether it
* should be remain the same size or be expandable with the container
* it is in.
*
* @param component the JComponent to be added to the current row
* @param horizontallyExpandable true if the component should expand horizontally
* with the surrounding container, false otherwise
* @param verticallyExpandable true if the component should expand vertically
* with the surrounding container, false otherwise
*/
public void addToRow(JComponent component, boolean horizontallyExpandable, boolean verticallyExpandable) {
constraints.gridx = gridx;
constraints.gridy = gridy;
int leftInsets;
int bottomInsets;
if ((gridy + 1) == rows) {
bottomInsets = 0;
} else {
bottomInsets = VERTICAL_COMPONENT_SPACING;
}
if (gridx == 0) {
leftInsets = 0;
} else {
leftInsets = HORIZONTAL_COMPONENT_SPACING;
}
constraints.insets = new Insets(0, leftInsets, bottomInsets, 0);
// if we've reached the end of the row (e.g. gridx is now 2 in a 2 column grid)
// - reset gridx back to 0
// - increment gridy (representing the next row)
if (gridx == columns) {
gridx = 0;
gridy++;
}
gridx++;
if (horizontallyExpandable) {
constraints.weightx = 1;
} else {
constraints.weightx = 0;
}
if (verticallyExpandable) {
constraints.weighty = 1;
} else {
constraints.weighty = 0;
}
constraints.gridwidth = 1;
constraints.gridheight = 1;
add(component, constraints);
}
/**
* Getter for the constraints object - should it be needed!
*
* @return the constraints object in the grid bag layout
*/
public GridBagConstraints getConstraints() {
return this.constraints;
}
/**
* Adds a JComponent to the grid bag layout using the specified constraints
* object. Mainly used internally, but public if more flexibility is
* required.
*
* @param component the JComponent to be added
* @param constraints the constraints object to be associated with the
* component when added
*/
public void add(JComponent component, GridBagConstraints constraints) {
layout.setConstraints(component, constraints);
add(component);
}
/**
* Getter for the current grid x position in the grid bag layout.
*
* @return the current grid x position in the grid bag layout
*/
public int getCurrentGridX() {
return gridx;
}
/**
* Getter for the current grid y position in the grid bag layout.
*
* @return the current grid y position in the grid bag layout
*/
public int getCurrentGridY() {
return gridy;
}
}
There's a lot of code here, but most of it is focussed around configuring the GridBagLayout to look good. Although it was written around 3 years ago, it does still work and this blog entry shows an example of how to use it and the results you can get. If it's helpful, feel free to take this and adapt it. To be honest, it's a good couple of years since I've done any hardcore Swing programming and I've not really kept up to date with the advancements in the API. If anybody has any examples of how similar forms can be developed using some of the newer APIs then it'd be great to compare and contrast.