|
A
GridBagLayout
is a layout manager that arranges the components in a container based on
GridBagConstraints
or other objects (e.g., special integer constants or doubles) that appear
in the container's
layout
array.
Components should be AWT or Swing components, however all layout managers
build a label (i.e., a
JLabel
or
Label)
appropriate for the container they are working on when they
find a
String
in the layout array where they expected a component.
Properties, like the font or foreground color, used by these short-hand
labels can not be directly specified, so they are inherited from the
container.
The organization of the container's layout array that is easiest to explain
and always works is the one in which every AWT or Swing component in the array
is immediately followed by a new
GridBagConstraints
object.
However another style that is now supported can sometimes lead to compact
descriptions of a container's layout.
In this style the Java code that examines the layout array allocates and
reuses one or more internal
GridBagConstraints
and decides what to do when it finds an unexpected object, like an
int,
double,
Insets,
or
Dictionary.
Components are automatically associated with a column and the internal
GridBagConstraints
allocated for that column is used unless the entry that follows the component
in the layout array is a
GridBagConstraints.
No matter which style is used, the end result is that the container is divided
into a rectangular grid of cells that do not necessarily have the same properties,
and each component is placed in the cells selected by its constraint.
The
GridBagConstraints
also include fields that control what happens to cells and the components
in those cells when the container is resized.
The fields in a
GridBagLayout
are:
| columns |
An
int
that can be used to specify the number of
columns
in the grid, but it only applies to the internally allocated
GridBagConstraints.
In other words, components that are immediately followed by their own
GridBagConstraints
in the layout array are not affected by
columns.
Assigning a positive integer to
columns
tells the low level Java code that processes the layout array that it should
allocate that many internal
GridBagConstraints
and the last one should have its
gridwidth
field permanently set to
REMAINDER,
which automatically ends the current row whenever it is used.
Components that are associated with a particular column can reuse the
GridBagConstraints
that was allocated for that column, which means they inherit properties,
like the
alignment,
that can be set when the first component is put in the column and never mentioned again.
When
columns
is
0
(the default) the layout array determines when rows end, and the Java code that
processes the layout array allocates a single internal
GridBagConstraints
that every component can reuse.
In other words, when a component uses the internal
GridBagConstraints
it inherits the settings stored by previous components,
unless it explicitly changes them.
Components are laid out horizontally and the row continues until there are no more
components or the integer constant
REMAINDER
is found in the layout array.
| | hgap |
A
double
that is
0
by default, that represents a fixed amount of horizontal padding,
in units of 72 dots per inch, that is added between all components.
| | model |
An
int
that is
1
(the default) if flexible processing of objects in the container's
layout array is enabled and
0
if the processing is strict and only accepts objects organized in pairs
that consist of a component and its
GridBagConstraints.
This field was occasionally used during our development work,
but both styles are now supported when
model
is
1,
so there is no reason why this field should be changed.
| | orientation |
An
int
that should be
NONE
(the default),
HORIZONTAL,
VERTICAL,
or
BOTH,
and is used to control direction of the padding added to the container when a
double
is found in the layout array.
When
orientation
is
HORIZONTAL
or
VERTICAL
a positive
double
in the layout array means rigid spacing (a strut) in the designated direction, a
0.0
means expandable spacing (glue) that stretches in that direction, and a negative
double
means rigid spacing that is perpendicular to that direction.
An
orientation
of
NONE
or
BOTH
behaves like
HORIZONTAL
until a component and its constraint end a row, but at that point any
double
that precedes the next component in the layout array it is treated as
vertical padding.
BOTH
switches back to
HORIZONTAL
mode after one
double,
but
NONE
waits for the next component.
| | type |
A read-only
int
that is set to
GRIDBAGLAYOUT,
which is defined in
yoix.awt
and
yoix.swing.
| | vgap |
A
double
that is
0
by default, that represents a fixed amount of vertical padding,
in units of 72 dots per inch, that is added between all components.
|
A component can be followed by a
GridBagConstraints
or one or more integer constants or
Insets
that set fields in the internal
GridBagConstraints
associated with that component.
An
Insets
is assigned to the
insets
field in the internal
GridBagConstraints.
Any integer constant that can be assigned to the
anchor
or
fill
fields in a
GridBagConstraints
is allowed.
Constants assigned to
fill
also set the
weightx
and
weighty
fields as is summarized below:
Constant fill weightx weighty
-------- ---- ------- -------
BOTH BOTH 1 1
HORIZONTAL HORIZONTAL 1 0
VERTICAL VERTICAL 0 1
NONE NONE 0 0
Sometimes you need a little more control over the
fill,
weightx,
and
weighty
fields, so twelve additional constants defined in
yoix.awt
and
yoix.swing,
are available and their behavior is summarized below:
Constant fill weightx weighty
-------- ---- ------- -------
BOTH_WEIGHTX BOTH 1 0
BOTH_WEIGHTY BOTH 0 1
BOTH_WEIGHT_NONE BOTH 0 0
HORIZONTAL_WEIGHTY HORIZONTAL 0 1
HORIZONTAL_WEIGHT_BOTH HORIZONTAL 1 1
HORIZONTAL_WEIGHT_NONE HORIZONTAL 0 0
NONE_WEIGHTX NONE 1 0
NONE_WEIGHTY NONE 0 1
NONE_WEIGHT_BOTH NONE 1 1
VERTICAL_WEIGHTX VERTICAL 1 0
VERTICAL_WEIGHT_BOTH VERTICAL 1 1
VERTICAL_WEIGHT_NONE VERTICAL 0 0
The only other integer constant that is recognized in the layout array is
REMAINDER,
which sets the
gridwidth
field to a value that ends the current row, but it is a temporary change
that is not saved in the internal
GridBagConstraints.
In other words, using
REMAINDER
to end a row is always allowed, even if
columns
is positive, but it does not affect what happens in the next row.
You can also take direct control over other the fields in the internal
GridBagConstraints,
but you have to do it using a
Dictionary
that explicitly defines the
GridBagConstraints
fields that you want to set, because if you used a
GridBagConstraints
none of the values would be saved.
In other words, an expression like
new Dictionary {
int gridx = 1;
int gridy = 1;
int weightx = 1;
}
in the layout array sets the
gridx,
gridy,
and
weightx
fields in the internal
GridBagConstraints.
The
hgap
and
vgap
fields are convenient when you want to separate components by fixed amounts,
but you can also throw a
double
into the layout array when you need extra spacing.
The value assigned to the
orientation
field and where you put the
double
in the layout array will determine whether you get horizontal or vertical padding.
Remember to include a decimal point in the number, because integers, as we
discussed earlier, mean something completely different.
The
GridBagLayout
is a powerful layout manager, and it is the one we use most,
but it can take time to master.
Part of the trouble, at least from our experience,
is that properties assigned to a component using
GridBagConstraints
can affect other components, particularly if those properties need to
be propagated horizontally or vertically to other cells in the grid.
Despite the difficulty, the
GridBagLayout
is an indispensable tool, so spend the time to learn it, but you probably
should start by trying to master the layout style in which every component
is followed by its own
GridBagConstraints.
| |
| Example: |
The program,
import yoix.*.*;
JFrame f = {
Insets border = {
double top = 72.0/8;
double left = 72.0/4;
double bottom = 72.0/8;
double right = 72.0/4;
};
Dimension size = {
double width = 10*72;
double height = 5*72;
};
Point location = {
double x = (VM.screen.width - size.width)/2;
double y = (VM.screen.height - size.height)/4;
};
GridBagLayout layoutmanager;
Array layout = {
new JLabel {
String text = "A Big Red Label";
String font = "Dialog-bold-16";
Color foreground = Color.red;
},
new GridBagConstraints {
int gridwidth = REMAINDER;
},
new JTextArea {
String tag = "$_textarea";
String font = "Monospaced-plain-12";
int scroll = AS_NEEDED;
int edit = TRUE;
},
new GridBagConstraints {
int gridwidth = REMAINDER;
int weightx = 1;
int weighty = 1;
int fill = BOTH;
},
new JPanel {
GridLayout layoutmanager;
Array layout = {
new JButton {
String text = "Update";
actionPerformed(e) {
String text = date() + "\n";
appendText(root.components.$_textarea, text);
}
},
new JButton {
String text = "Clear";
actionPerformed(e) {
root.components.$_textarea.text = "";
}
},
new JButton {
String text = "Dismiss";
actionPerformed(e) {
exit(0);
}
},
};
},
new GridBagConstraints {
int gridwidth = REMAINDER;
Insets insets = {
double top = 72.0/8;
};
},
};
};
f.visible = TRUE;
is a simple example that uses standard
GridBagLayout
techniques and here is the same screen, rewritten to use some of the new
layout techniques allowed when the
model
field is non-zero:
import yoix.*.*;
JFrame f = {
Insets border = {
double top = 72.0/8;
double left = 72.0/4;
double bottom = 72.0/8;
double right = 72.0/4;
};
Dimension size = {
double width = 10*72;
double height = 5*72;
};
Point location = {
double x = (VM.screen.width - size.width)/2;
double y = (VM.screen.height - size.height)/4;
};
GridBagLayout layoutmanager = {
int columns = 1;
};
Array layout = {
new JLabel {
String text = "A Big Red Label";
String font = "Dialog-bold-16";
Color foreground = Color.red;
},
NONE,
new JTextArea {
String tag = "$_textarea";
String font = "Monospaced-plain-12";
int scroll = AS_NEEDED;
int edit = TRUE;
},
BOTH,
72.0/8, // vertical padding
new JPanel {
GridLayout layoutmanager;
Array layout = {
new JButton {
String text = "Update";
actionPerformed(e) {
String text = date() + "\n";
appendText(root.components.$_textarea, text);
}
},
new JButton {
String text = "Clear";
actionPerformed(e) {
root.components.$_textarea.text = "";
}
},
new JButton {
String text = "Dismiss";
actionPerformed(e) {
exit(0);
}
},
};
},
NONE,
};
};
f.visible = TRUE;
Notice how we use the integer constants
BOTH
and
NONE
to implicitly reset the
fill,
weightx,
and
weighty,
fields for the three components that were added to the
JFrame's
layout array.
We encourage you to experiment with these scripts.
For example, can you explain what happens when you remove
NONE
from the button panel in the last example?
In practice we usually use the original
GridBagLayout
style for top-level containers, like a
JFrame
or
JDialog,
but we often choose the new style to describe the layout in a
JPanel.
Here is a script,
import yoix.*.*;
JDialog screen = {
Dimension size = NULL;
String font = "Dialog-bold-12";
double border = 72.0/8;
int modal = TRUE;
Thread thrd;
GridBagLayout layoutmanager;
Array layout = {
new JLabel {
String text = "Example Login Screen";
String font = "Dialog-bold-16";
Color foreground = Color.red;
},
new GridBagConstraints {
int gridwidth = REMAINDER;
},
new JPanel {
GridBagLayout layoutmanager = {
int columns = 2;
double vgap = 72.0/32;
};
Array layout = {
"Username",
RIGHT,
new JTextField {
String tag = "$_username";
int columns = 10;
int requestfocus = TRUE;
textValueChanged(e) {
root.components.$_failed.text = "";
}
},
LEFT,
"Password",
new JTextField {
String tag = "$_password";
int columns = 10;
int echo = '*';
textValueChanged(e) {
root.components.$_failed.text = "";
}
},
"Group",
new JTextField {
String tag = "$_group";
int columns = 10;
textValueChanged(e) {
root.components.$_failed.text = "";
}
},
};
},
new GridBagConstraints {
int gridwidth = REMAINDER;
int ipadx = 3.0*72;
Insets insets = {
double top = 72.0/4;
};
},
new JLabel {
String tag = "$_failed";
Color foreground = Color.red;
},
new GridBagConstraints {
int gridwidth = REMAINDER;
int weighty = 1;
Insets insets = {
double top = 72.0/4;
double bottom = 72.0/4;
};
},
new JPanel {
GridLayout layoutmanager;
Array layout = {
new JButton {
String text = "OK";
actionPerformed(e) {
root.thrd.queue(&root.Login);
}
},
new JButton {
String text = "Quit";
Color foreground = Color.red;
actionPerformed(e) {
exit(0);
}
},
};
},
new GridBagConstraints {
int gridwidth = REMAINDER;
Insets insets = {
double top = 72.0/8;
};
},
};
Login() {
components.$_failed.text = "";
sleep(1.0);
components.$_failed.text = "Login failed - try again";
}
ShowScreen() {
Point point;
if (!visible) {
point.x = (VM.screen.width - size.width)/2;
point.y = (VM.screen.height - size.height)/2 - 72.0;
location = point;
visible = TRUE;
}
}
};
screen.ShowScreen();
that builds and displays a simple login screen.
Notice how we mixed the styles and also used the automatic substitution of
JLabels
for text strings.
Once again we encourage you to experiment with this script.
For example, try adding some padding, say
72.0,
to the layout array responsible for the labels and textfields and see if
you understand what happens.
Notice that you can get horizontal or vertical spacing, depending on where
you put the padding.
We also often use a
GridBagLayout
when we want to center buttons in a screen and put other components
in the same row but anchor them to the left or right side of the screen.
Wrapping an extra
JPanel
around the buttons in the last example gives us the script,
import yoix.*.*;
JDialog screen = {
Dimension size = NULL;
String font = "Dialog-bold-12";
double border = 72.0/8;
int modal = TRUE;
GridBagLayout layoutmanager;
Array layout = {
new JLabel {
String text = "Example Login Screen";
String font = "Dialog-bold-16";
Color foreground = Color.red;
},
new GridBagConstraints {
int gridwidth = REMAINDER;
},
new JPanel {
GridBagLayout layoutmanager = {
int columns = 2;
double vgap = 72.0/32;
};
Array layout = {
"Username",
RIGHT,
new JTextField {
String tag = "$_username";
int columns = 10;
int requestfocus = TRUE;
textValueChanged(e) {
root.components.$_failed.text = "";
}
},
LEFT,
"Password",
new JTextField {
String tag = "$_password";
int columns = 10;
int echo = '*';
textValueChanged(e) {
root.components.$_failed.text = "";
}
},
"Group",
new JTextField {
String tag = "$_group";
int columns = 10;
textValueChanged(e) {
root.components.$_failed.text = "";
}
},
};
},
new GridBagConstraints {
int gridwidth = REMAINDER;
int ipadx = 3.0*72;
Insets insets = {
double top = 72.0/4;
};
},
new JLabel {
String tag = "$_failed";
Color foreground = Color.red;
},
new GridBagConstraints {
int gridwidth = REMAINDER;
int weighty = 1;
Insets insets = {
double top = 72.0/4;
double bottom = 72.0/4;
};
},
new JPanel {
GridBagLayout layoutmanager;
Array layout = {
new JPanel {
GridLayout layoutmanager;
Array layout = {
new JButton {
String text = "OK";
actionPerformed(e) {
root.Login();
}
},
new JButton {
String text = "Quit";
Color foreground = Color.red;
actionPerformed(e) {
exit(0);
}
},
};
},
//
// Set defaults so everything ends
// up in the same cell.
//
new Dictionary {
int gridx = 1;
int gridy = 1;
int weightx = 1;
},
new JChoice {
String selected = "two";
Array items = {
"First", "one",
"Second", "two",
"Three", "three",
};
},
RIGHT,
};
},
new GridBagConstraints {
int gridwidth = REMAINDER;
int weightx = 1;
int fill = HORIZONTAL;
Insets insets = {
double top = 72.0/8;
};
},
};
Login() {
components.$_failed.text = "";
sleep(1.0);
components.$_failed.text = "Login failed - try again";
}
ShowScreen() {
Point point;
if (!visible) {
point.x = (VM.screen.width - size.width)/2;
point.y = (VM.screen.height - size.height)/2 - 72.0;
location = point;
visible = TRUE;
}
}
};
screen.ShowScreen();
and if you look carefully you will see that the technique that we
used basically added the buttons and the choice to the same cell.
The buttons are anchored to the center of the cell and the choice
is anchored to the right side, so we get the layout behavior that
we are looking for if the new
JPanel
horizontally fills the available space and the screen has a border
that is horizontally symmetric.
| | |
| See Also: |
BorderLayout,
BoxLayout,
CardLayout,
CustomLayout,
FlowLayout,
GridLayout,
LayoutManager
|
|