GridBagLayout
is a very flexible layout manager that allows you to position
components relative to one another using constraints. With
GridBagLayout
(and a fair amount of effort), you
can create almost any imaginable layout. Components are arranged at
logical coordinates on an abstract grid. We’ll call them
“logical” coordinates because they really designate
positions in the space of rows and columns formed by the set of
components.
Rows
and columns of the grid stretch to different sizes, based on the
sizes and constraints of the components they hold.
A row or column in a GridBagLayout
expands to
accommodate the dimensions and constraints of the largest component
it contains. Individual components may span more than one row or
column. Components that aren’t as large as their grid cell can
be anchored within their cell. They can also be set to fill or to
expand their size in either dimension. Extra area in the grid rows
and columns can be parceled out according to the weight constraints
of the components. In this way, you can control how various
components will grow and stretch when a window is resized.
GridBagLayout
is much easier to use in a graphical
WYSIWYG GUI builder environment.
That’s because working with GridBag
is kind
of like messing with the “rabbit ears” antennae on your
television. It’s not particularly difficult to get the results
that you want through trial and error, but writing out hard and fast
rules for how to go about it is difficult. In short,
GridBagLayout
is complex and has some quirks. It
is also simply a bit ugly both in model and implementation. Remember
that you can do a lot with nested panels and by composing simpler
layout managers within one another. If you look back through this
chapter, you’ll see many examples of composite layouts;
it’s up to you to determine how far you should go before making
the break from simpler layout managers to a more complex all-in-one
layout manager like GridBagLayout
.
Having said that
GridBagLayout
is complex and a bit ugly,
we’re going to contradict ourselves and say that it’s
surprisingly simple. There is only one constructor with no arguments
(GridBagLayout( )
), and there aren’t a lot
of fancy methods to control how the display works.
The appearance of a grid bag layout is controlled by sets of
GridBagConstraints
, and that’s where things
get hairy. Each component managed by a
GridBagLayout
is associated with a
GridBagConstraints
object.
GridBagConstraints
holds the following variables,
which we’ll describe in detail shortly:
int gridx, gridy
Controls the position of the component on the layout’s grid.
int weightx, weighty
Controls how additional space in the row or column is allotted to the component.
int fill
Controls whether the component expands to fill the space allotted to it.
int gridheight, gridwidth
Controls the number of rows or columns the component spans.
int anchor
Controls the position of the component if there is extra room within the space allotted to it.
int ipadx, ipady
Controls padding between the component and the borders of its area.
Insets insets
Controls padding between the component and neighboring components.
To make a set of constraints for a component or components, create a
new instance of GridBagConstraints
and set these
public variables to the appropriate values. There are no pretty
constructors, and there’s not much else to the class at all.
The easiest way to associate a set of constraints with a component
is to use the version of add( )
that takes both a component object and a layout object as
arguments. This puts the component in the container and associates
the GridBagConstraints
object with it:
Container content = getContentPane( ); JComponent component = new JLabel("constrain me, please..."); GridBagConstraints constraints = new GridBagConstraints( ); constraints.gridx = x; constraints.gridy = y; ... content.add(component, constraints);
You can also add a component to a GridBagLayout
by
using the single argument add( )
method, and then
later calling
the
layout’s setConstraints( )
method directly,
to pass it the GridBagConstraints
object for that
component:
add(component); ... myGridBagLayout.setConstraints(component, constraints);
In either case, the set of constraints is copied when it is applied
to the component. It’s the individual constraints that apply to
the component, not the GridBagConstraints
object.
Therefore, you’re free to create a single set of
GridBagConstraints
, modify it as needed, and apply
it as needed to different objects. You might want to create a helper
method that sets the constraints appropriately, then adds the
component, with its constraints, to the layout. That’s the
approach we’ll take in our examples; our helper method is
called addGB( )
, and it takes a component plus a
pair of coordinates as arguments. These coordinates become the
gridx
and gridy
values for the
constraints. We could expand upon this later and overload
addGB( )
to take more parameters for other
constraints that we often change from component to component.
One
of the biggest surprises in the GridBagLayout
is
that there’s no way to specify the size of the grid. There
doesn’t have to be. The grid size is determined implicitly by
the constraints of all the objects; the layout manager picks
dimensions large enough so that everything fits. Thus, if you put one
component in a layout and set its gridx
and
gridy
constraints to 25, the layout manager
creates a 25 × 25 grid, with rows and columns both numbered
from 0 to 24. If you then add a second component with a
gridx
of 30 and a gridy
of 13,
the grid’s dimensions change to 30 × 25. You don’t
have to worry about setting up an appropriate number of rows and
columns. The layout manager does it automatically, as you add
components.
With this knowledge, we’re ready to create some simple
displays. We’ll start by arranging a group of components in a
cross shape. We maintain explicit
x
and
y
local variables, setting them as we add the
components to our grid. This is partly for clarity, but it can be a
handy technique when you want to add a number of components in a row
or column. You can simply increment gridx
or
gridy
before adding each component. This is a
simple and problem-free way to achieve relative placement. (Later,
we’ll describe GridBagConstraints
’s
RELATIVE
constant, which does relative placement
automatically.) Here’s our first layout (see Figure 16.7):
//file: GridBag1.java import java.awt.*; import java.awt.event.*; import javax.swing.*; public class GridBag1 extends JPanel { GridBagConstraints constraints = new GridBagConstraints( ); public GridBag1( ) { setLayout(new GridBagLayout( )); int x, y; // for clarity addGB(new JButton("North"), x = 1, y = 0); addGB(new JButton("West"), x = 0, y = 1); addGB(new JButton("Center"), x = 1, y = 1); addGB(new JButton("East"), x = 2, y = 1); addGB(new JButton("South"), x = 1, y = 2); } void addGB(Component component, int x, int y) { constraints.gridx = x; constraints.gridy = y; add(component, constraints); } public static void main(String[] args) { JFrame f = new JFrame("GridBag1"); f.addWindowListener(new WindowAdapter( ) { public void windowClosing(WindowEvent e) { System.exit(0); } }); f.setSize(225, 150); f.setLocation(200, 200); f.setContentPane(new GridBag1( )); f.setVisible(true); } }
The buttons in this example are “clumped” together in the center of their display area. Each button is displayed at its preferred size, without stretching to fill the available space. This is how the layout manager behaves when the "weight” constraints are left unset. We’ll talk more about weights in the next two sections.
Let’s make the buttons expand
to fill the entire JFrame
window. To do so, we
must take two steps: we must set the fill
constraint for each button to the value BOTH
, and
we must set the weightx
and
weighty
to nonzero values, as shown in the
following example. Figure 16.8 shows the
resulting layout.
//file: GridBag2.java import java.awt.*; import java.awt.event.*; import javax.swing.*; public class GridBag2 extends JPanel { GridBagConstraints constraints = new GridBagConstraints( ); public GridBag2( ) { setLayout(new GridBagLayout( )); constraints.weightx = 1.0; constraints.weighty = 1.0; constraints.fill = GridBagConstraints.BOTH; int x, y; // for clarity addGB(new JButton("North"), x = 1, y = 0); addGB(new JButton("West"), x = 0, y = 1); addGB(new JButton("Center"), x = 1, y = 1); addGB(new JButton("East"), x = 2, y = 1); addGB(new JButton("South"), x = 1, y = 2); } void addGB(Component component, int x, int y) { constraints.gridx = x; constraints.gridy = y; add(component, constraints); } public static void main(String[] args) { JFrame f = new JFrame("GridBag2"); f.addWindowListener(new WindowAdapter( ) { public void windowClosing(WindowEvent e) { System.exit(0); } }); f.setSize(225, 150); f.setLocation(200, 200); f.setContentPane(new GridBag2( )); f.setVisible(true); } }
BOTH
is one of the constants of the
GridBagConstraints
class; it tells the component
to fill the available space in both directions. Here are the
constants you can use to set the fill
field:
HORIZONTAL
Fill the available horizontal space.
VERTICAL
Fill the available vertical space.
BOTH
Fill the available space in both directions.
NONE
Don’t fill the available space; display the component at its preferred size.
We set the weight constraints to 1.0; in this example it doesn’t matter what they are, provided that each component has the same nonzero weight. Filling doesn’t occur if the component weights in the direction you’re filling are 0, which is the default value.
One of the most important features of
GridBaglayout
is that it lets you create
arrangements in which components span two or more rows or columns. To
do so, set the gridwidth
and
gridheight
variables of the
GridBagConstraints
.
Here’s an example that creates such a display; button one spans
two columns vertically, and button four spans two horizontally (see
Figure 16.9):
//file: GridBag3.java import java.awt.*; import java.awt.event.*; import javax.swing.*; public class GridBag3 extends JPanel { GridBagConstraints constraints = new GridBagConstraints( ); public GridBag3( ) { setLayout(new GridBagLayout( )); constraints.weightx = 1.0; constraints.weighty = 1.0; constraints.fill = GridBagConstraints.BOTH; int x, y; // for clarity constraints.gridheight = 2; // span two rows addGB(new JButton("one"), x = 0, y = 0); constraints.gridheight = 1; // set it back addGB(new JButton("two"), x = 1, y = 0); addGB(new JButton("three"), x = 2, y = 0); constraints.gridwidth = 2; // span two columns addGB(new JButton("four"), x = 1, y = 1); constraints.gridwidth = 1; // set it back } void addGB(Component component, int x, int y) { constraints.gridx = x; constraints.gridy = y; add(component, constraints); } public static void main(String[] args) { JFrame f = new JFrame("GridBag3"); f.addWindowListener(new WindowAdapter( ) { public void windowClosing(WindowEvent e) { System.exit(0); } }); f.setSize(200, 200); f.setLocation(200, 200); f.setContentPane(new GridBag3( )); f.setVisible(true); } }
The size of each element is controlled by the
gridwidth
and gridheight
values
of its constraints. For button one, we set
gridheight
to 2. Therefore, it is two cells high;
its gridx
and gridy
positions
are both zero, so it occupies cell (0,0) and the cell directly below
it, (0,1). Likewise, button four has a gridwidth
of 2 and a gridheight
of 1, so it occupies two
cells horizontally. We place this button in cell (1,1), so it
occupies that cell and its neighbor, (2,1).
In this example, we set the
fill
to BOTH
and
weightx
and weighty
to 1 for
all components. By doing so, we told each button to occupy all the
space available. Strictly speaking, this isn’t necessary.
However, it makes it easier to see exactly how much space each button
occupies.
The
weightx
and weighty
variables
of a GridBagConstraints
object determine how
“extra” space in the container is distributed among the
columns or rows in the layout. As long as you keep things simple, the
effect these variables have is fairly intuitive: the larger the
weight, the greater the amount of space allocated to the component.
Figure 16.10 shows what happens if we vary the
weightx
constraint from 0.1 to 1.0 as we place
three buttons in a row.
//file: GridBag4.java import java.awt.*; import java.awt.event.*; import javax.swing.*; public class GridBag4 extends JPanel { GridBagConstraints constraints = new GridBagConstraints( ); public GridBag4( ) { setLayout(new GridBagLayout( )); constraints.fill = GridBagConstraints.BOTH; constraints.weighty = 1.0; int x, y; // for clarity constraints.weightx = 0.1; addGB(new JButton("one"), x = 0, y = 0); constraints.weightx = 0.5; addGB(new JButton("two"), ++x, y); constraints.weightx = 1.0; addGB(new JButton("three"), ++x, y); } void addGB(Component component, int x, int y) { constraints.gridx = x; constraints.gridy = y; add(component, constraints); } public static void main(String[] args) { JFrame f = new JFrame("GridBag4"); f.addWindowListener(new WindowAdapter( ) { public void windowClosing(WindowEvent e) { System.exit(0); } }); f.setSize(300, 100); f.setLocation(200, 200); f.setContentPane(new GridBag4( )); f.setVisible(true); } }
The specific values of the weights are not meaningful; it is only their relative proportions that matter. After the preferred sizes of the components (including padding and insets—see the next section) are determined, any extra space is doled out in proportion to the component’s weights. So, for example, if each of our three components had the same weight each would receive a third of the extra space. To make this more obvious, you may prefer to express the weights for a row or column as fractions totaling 1.0—for example: 0.25, 0.25, 0.50. Components with a weight of 0 receive no extra space.
The situation is a bit more complicated when there are multiple rows
or columns and when there is even the possibility of components
spanning more than one cell. In the general case,
GridBagLayout
calculates an effective overall
weight for each for each row and each column and then distributes the
extra space to them proportionally. Note that our single row example
above is just a special case where the columns each have one
component. The gory details of the calculations follow.
For a given row or column
(“rank”), GridBagLayout
first
considers the weights of all of the components contained strictly
within that rank—ignoring those that span more than one cell.
The greatest individual weight becomes the overall weight of the row
or column. Intuitively this means that
GridBagLayout
is trying to accommodate the needs
of the weightiest component in that rank.
Next, GridBagLayout
considers the components that
occupy more than one cell. Here things get a little weird.
GridbagLayout
wants to evaluate them like the
others, to see whether they affect the determination of the largest
weight in a row or column. However, because these components occupy
more than one cell, GridBagLayout
divides their
weight among the ranks (rows or columns) that they span.
GridBagLayout
tries to calculate an effective
weight for the portion of the component that occupies each of its
rows or columns. It does this by trying to divide the weight of the
component among the ranks in the same proportions that the length (or
height) of the component will be shared by the ranks. But how does it
know what the proportions will be before the whole grid is
determined? That’s what it’s trying to calculate after
all. It simply guesses based on the row or column weights already
determined. GridbagLayout
uses the weights
determined by the first round of calculations to split up the weight
of the component over the ranks that it occupies. For each row or
column, it then considers that fraction of the weight to be the
component’s weight for that rank. That weight then contends for
the “heaviest weight” in the row or column, possibly
changing the overall weight of that row or column,
as we described
earlier.
If a component is smaller than the space
available for it, it is centered by default. But centering
isn’t the only possibility. The anchor
constraint tells a grid bag layout how to position a component within
its cell in the grid. Possible values are:
GridBagConstraints.CENTER
,
NORTH
, NORTHEAST
,
EAST
, SOUTHEAST
,
SOUTH
, SOUTHWEST
,
WEST
, and NORTHWEST
. For
example, an anchor of GridBagConstraints.NORTH
centers a component at the top of its display area;
SOUTHEAST
places a component at the bottom-right
corner of its area.
Another way to
control the behavior of a component in a grid bag layout is to use
padding and insets. Padding is determined by the
ipadx
and ipady
fields of
GridBagConstraints
. They specify horizontal and
vertical “growth factors” for the component. In Figure 16.11, the West button is larger because we have set the
ipadx
and ipady
values of its
constraints to 25. Therefore, the layout manager gets the
button’s preferred size and adds 25 pixels in each direction to
determine the button’s actual size. The sizes of the other
buttons are unchanged because their padding is set to 0 (the default), but their spacing is different. The West button is unnaturally tall, which means
that the middle row of the layout must be taller than the others.
//file: GridBag5.java import java.awt.*; import java.awt.event.*; import javax.swing.*; public class GridBag5 extends JPanel { GridBagConstraints constraints = new GridBagConstraints( ); public GridBag5( ) { setLayout(new GridBagLayout( )); int x, y; // for clarity addGB(new JButton("North"), x = 1, y = 0); constraints.ipadx = 25; // add padding constraints.ipady = 25; addGB(new JButton("West"), x = 0, y = 1); constraints.ipadx = 0; // remove padding constraints.ipady = 0; addGB(new JButton("Center"), x = 1, y = 1); addGB(new JButton("East"), x = 2, y = 1); addGB(new JButton("South"), x = 1, y = 2); } void addGB(Component component, int x, int y) { constraints.gridx = x; constraints.gridy = y; add(component, constraints); } public static void main(String[] args) { JFrame f = new JFrame("GridBag5"); f.addWindowListener(new WindowAdapter( ) { public void windowClosing(WindowEvent e) { System.exit(0); } }); f.setSize(250, 250); f.setLocation(200, 200); f.setContentPane(new GridBag5( )); f.setVisible(true); } }
Notice that the horizontal padding, ipadx
, is
added on both the left and right sides of the button. Therefore, the
button grows horizontally by twice the value of
ipadx
. Likewise, the vertical padding,
ipady
, is added on both the top and the bottom.
Insets add space between the edges of the component and its cell.
They are stored in the insets
field of
GridBagConstraints
, which is an
Insets
object. An Insets
object
has four fields, to specify the margins on the
top
, bottom
,
left
, and right
of the
component. The relationship between
insets and padding can be confusing.
As shown in Figure 16.12, padding is added to
the component itself, increasing its size. Insets are external to the
component and represent the margin between the component and its
cell.
Padding and weighting have an odd interaction with each other. If you
use padding, it’s best to use the default
weightx
and weighty
values for
each
component.
In
all of
our grid bag layouts so far, we
have specified the gridx
and
gridy
coordinates of each component explicitly
using its constraints. Another alternative is relative
positioning.
Conceptually, relative positioning is simple: we simply say
“put this component to the left of (or below) the previous
component.” To do so, set gridx
or
gridy
to the constant
GridBagConstraints.RELATIVE
. Unfortunately,
it’s not as simple as this. Here are a couple of warnings:
To place a component to the right of the previous one, set
gridx
to RELATIVE
and use the same value for
gridy
as you used for the previous component.
Similarly, to place a component below the previous one, set
gridy
to RELATIVE
and leave gridx
unchanged.
Setting both gridx
and gridy
to
RELATIVE
places all the components in one row, not
in a diagonal line, as you would expect. (This is the default.)
In other words, if gridx
or
gridy
is RELATIVE
, you had
better leave the other value unchanged. RELATIVE
makes it easy to arrange a lot of components in a row or a column.
That’s what it was intended for; if you try to do something
else, you’re fighting against the layout manager, not working
with it.
GridBagLayout
allows another kind of relative
positioning, in which you specify where, in a row or a column, the
component should be placed. To do so, you use the
gridwidth
and gridheight
fields
of GridBagConstraints
. Setting either of these to
the constant REMAINDER
says that the component
should be the last item in its row or column, and therefore should
occupy all the remaining space. Setting either
gridwidth
or gridheight
to
RELATIVE
says that it should be the second to the
last item in its row or column. Unfortunately, you can use these
constants to create constraints that can’t possibly be met; for
example, you can say that two components must be the last component
in a row. In these cases, the layout manager tries to do something
reasonable—but it will almost certainly do something you
don’t want. Again, relative placement works well as long as you
don’t try to twist it into doing something it wasn’t
designed for.
Sometimes things don’t fall neatly
into little boxes. This is true of layouts as well as life. For
example, if you want to use some of
GridBagLayout
’s weighting features for part
of your GUI, you could create separate layouts for different parts of
the GUI and combine them with yet another layout. That’s how
we’ll build the pocket calculator interface in Figure 16.13. We will use three grid bag layouts: one
for the first row of buttons (C, %, +), one for the last (0, ., =),
and one for the window itself. The master layout (the window’s)
manages the text field we use for the display, the panels containing
the first and last rows of buttons, and the twelve buttons in the
middle.[46]
Here’s the code for the Calculator
example.
It implements only the user interface (i.e., the keyboard); it
collects everything you type in the display field, until you press
C (clear). Figuring out how to
connect the GUI to some other code that would perform the operations
is up to you. One strategy would be to send an event to the object
that does the computation whenever the user presses the equals sign.
That object could read the contents of the text field, parse it, do
the computation, and display the results.
//file: Calculator.java import java.awt.*; import java.awt.event.*; import javax.swing.*; public class Calculator extends JPanel implements ActionListener { GridBagConstraints gbc = new GridBagConstraints( ); JTextField theDisplay = new JTextField( ); public Calculator( ) { gbc.weightx = 1.0; gbc.weighty = 1.0; gbc.fill = GridBagConstraints.BOTH; ContainerListener listener = new ContainerAdapter( ) { public void componentAdded(ContainerEvent e) { Component comp = e.getChild( ); if (comp instanceof JButton) ((JButton)comp).addActionListener(Calculator.this); } }; addContainerListener(listener); gbc.gridwidth = 4; addGB(this, theDisplay, 0, 0); // make the top row JPanel topRow = new JPanel( ); topRow.addContainerListener(listener); gbc.gridwidth = 1; gbc.weightx = 1.0; addGB(topRow, new JButton("C"), 0, 0); gbc.weightx = 0.33; addGB(topRow, new JButton("%"), 1, 0); gbc.weightx = 1.0; addGB(topRow, new JButton("+"), 2, 0 ); gbc.gridwidth = 4; addGB(this, topRow, 0, 1); gbc.weightx = 1.0; gbc.gridwidth = 1; // make the digits for(int j=0; j<3; j++) for(int i=0; i<3; i++) addGB(this, new JButton("" + ((2-j)*3+i+1) ), i, j+2); // -, x, and divide addGB(this, new JButton("-"), 3, 2); addGB(this, new JButton("x"), 3, 3); addGB(this, new JButton("u00F7"), 3, 4); // make the bottom row JPanel bottomRow = new JPanel( ); bottomRow.addContainerListener(listener); gbc.weightx = 1.0; addGB(bottomRow, new JButton("0"), 0, 0); gbc.weightx = 0.33; addGB(bottomRow, new JButton("."), 1, 0); gbc.weightx = 1.0; addGB(bottomRow, new JButton("="), 2, 0); gbc.gridwidth = 4; addGB(this, bottomRow, 0, 5); } void addGB(Container cont, Component comp, int x, int y) { if ((cont.getLayout( ) instanceof GridBagLayout) == false) cont.setLayout(new GridBagLayout( )); gbc.gridx = x; gbc.gridy = y; cont.add(comp, gbc); } public void actionPerformed(ActionEvent e) { if (e.getActionCommand( ).equals("C")) theDisplay.setText(""); else theDisplay.setText(theDisplay.getText( ) + e.getActionCommand( )); } public static void main(String[] args) { JFrame f = new JFrame("Calculator"); f.addWindowListener(new WindowAdapter( ) { public void windowClosing(WindowEvent e) { System.exit(0); } }); f.setSize(200, 250); f.setLocation(200, 200); f.setContentPane(new Calculator( )); f.setVisible(true); } }
Once again, we use an addGB( )
helper method to
add components with their constraints to the layout. Before
discussing how to build the layout, let’s look at
addGB( )
. We said earlier that three layout
managers are in our user interface: one for the application panel
itself, one for the panel containing the first row of buttons
(topRow
), and one for the panel containing the
bottom row of buttons (bottomRow
). We use
addGB( )
for all three layouts; its first argument
specifies the container to add the component to. Thus, when the first
argument is this
, we’re adding an object to
the content pane of the JFrame
. When the first
argument is topRow
, we’re adding a button to
the first row of buttons. addGB( )
first checks
the container’s layout manager, and sets it to
GridBagLayout
if it isn’t already set
properly. It sets the object’s position by modifying a set of
constraints, gbc
, and then uses these constraints
to add the object to the container.
We use a single set of constraints throughout the example, modifying
fields as we see fit. The constraints are initialized in
Calculator
’s constructor. Before calling
addGB( )
, we set any fields of
gbc
for which the defaults are inappropriate.
Thus, for the answer display, we set the grid width to 4, and add the
answer display directly to the application panel
(this
). The add( )
method,
which is called by addGB( )
, makes a copy of the
constraints, so we’re free to reuse gbc
throughout the application.
The first and last rows of buttons motivate the use of multiple
GridBagLayout
containers, each with its own grid.
These buttons appear to straddle grid lines, but you really
can’t accomplish this using a single grid. Therefore,
topRow
has its own layout manager, with three
horizontal cells, allowing each button in the row to have a grid
width of 1. To control the size of the buttons, we set the
weightx
variables so that the clear and plus
buttons take up more space than the percent button. We then add the
topRow
as a whole to the application, with a grid
width of 4. The bottom row is built similarly.
To build the buttons for the digits 1 through 9, we use a doubly
nested loop. There’s nothing particularly interesting about
this loop, except that it’s probably a bit too clever for good
taste. The minus, multiply, and divide buttons are also simple: we
create a button with the appropriate label and use addGB( )
to place it in the application. It’s worth noting
that we used a Unicode constant to request a real division sign,
rather than wimping out and using a slash.
That’s it for the user interface; what’s left is event
handling. Each button generates action events; we need to register
listeners for these events. We’ll make the application panel,
the Calculator
, the listener for all the buttons.
To register the Calculator
as a listener,
we’ll be clever. Whenever a component is added to a container,
the container generates a
ContainerEvent
. We use an anonymous inner
ContainerListener
to register listeners for our
buttons. This means that the Calculator
must
register as a ContainerListener
for itself, and
for the two panels, topRow
and
bottomRow
. The componentAdded( )
method is very simple. It calls getChild( )
to
find out what component caused the event (i.e., what component was
added). If that component is a button, it registers the
Calculator
as an ActionListener
for that button.
actionPerformed( )
is called whenever the user
presses any button. It clears the display if the user pressed the C
button; otherwise, it appends the button’s action command (in
this case, its label) to the display.
Combining layout managers is an extremely useful trick. Granted, this
example verges on overkill. You won’t often need to create a
composite layout using multiple grid bags. Composite layouts are most
common with BorderLayout
; you’ll frequently
use different layout managers for each of a border layout’s
regions. For example, the CENTER
region might be a
ScrollPane
, which has its own special-purpose
layout manager; the EAST
and
SOUTH
regions might be panels managed by grid
layouts or flow layouts,
as
appropriate.
[46] If you’re curious, this calculator is based on the ELORG-801, encountered in an online “calculator museum”; see http://www.taswegian.com/MOSCOW/elorg801.html.