A layout manager arranges the child components of a container, as shown in Figure 19-1. It positions and sets the size of components within the container’s display area according to a particular layout scheme. The layout manager’s job is to fit the components into the available area while maintaining some spatial relationships among them. AWT and Swing come with several standard layout managers that will collectively handle most situations; you can also make your own layout managers if you have special requirements.
Every container has a default layout manager. When you make a new
container, it comes with a LayoutManager
object of the
appropriate type. You can install a new layout manager at any time by using
the setLayout()
method. For
example, we can set the layout manager of a Swing container to a type called
BorderLayout
like so:
myContainer
.
setLayout
(
new
BorderLayout
()
);
Notice that although we have created a BorderLayout
, we haven’t
bothered to save a reference to it. This is typical; after installing a
layout manager, it usually does its work behind the scenes by interacting
with the container. You rarely call the layout manager’s methods directly,
so you don’t usually need a reference (a notable exception is CardLayout
). However, you do need to know what the
layout manager is going to do with your components as you work with
them.
The LayoutManager
is consulted
whenever a container’s doLayout()
method is called
to reorganize the contents. It does its job by calling the setLocation()
or setBounds()
methods of the
individual child components to arrange them in the container’s display area.
A container is laid out the first time it is displayed and thereafter
whenever the container’s revalidate()
method is
called. Containers that are a subclass of the Window
class (Frame
, JFrame
,
and JWindow
) are automatically validated
whenever they are packed or resized. Calling pack()
sets the window’s
size as small as possible while granting all its components their preferred
sizes.
Every component provides three important pieces of information used by
the layout manager in placing and sizing it: a minimum size, a maximum size,
and a preferred size. These sizes are reported by the getMinimumSize()
,
getMaximumSize()
, and
getPreferredSize()
methods
of Component
, respectively. For example,
a plain JButton
object can normally be
changed to any size. However, the button’s designer can provide a preferred
size for a good-looking button. The layout manager might use this size when
there are no other constraints, or it might ignore it, depending on its
scheme. If we give the button a label, the button may need a new minimum
size to display itself properly. The layout manager should generally respect
the button’s minimum size and guarantee that it has at least that much
space. Similarly, a particular component might not be able to display itself
properly if it is too large (perhaps it has to scale up an image); it can
use getMaximumSize()
to report the
largest size it considers acceptable.
The preferred size of a Container
object has the same meaning as for any other type of component. However,
because a Container
may hold its own
components and want to arrange them in its own layout, its preferred size is
a function of its layout manager. The layout manager is, therefore, involved
in both sides of the issue. It asks the components in its container for
their preferred (or minimum) sizes in order to arrange them. Based on those
values, it calculates the preferred size for its own container (which can
then be communicated to the container’s parent and so on).
When a layout manager is called to arrange its components, it is working within a fixed area. It usually begins by looking at its container’s dimensions and the preferred or minimum sizes of the child components. It then doles out screen area and sets the sizes of components according to its scheme and specific constraints.
You can set the minimum, preferred, and maximum sizes for a component
with the setMinimumSize()
,
setMaximumSize()
, and
setPreferredSize()
methods.
Take care when setting these properties because generally those values
should be calculated based on the real conditions of the component, not just
fixed at a static value that looks good in one particular case. You can
override the getMinimumSize()
,
getMaximumSize()
, and
getPreferredSize()
methods
of your own components to allow them to calculate those values, but you
should do this only if you are specializing the component and it has new
needs. In general, if you find yourself fighting with a layout manager
because it’s changing the size of one of your components, you are probably
using the wrong kind of layout manager or not composing your user interface
properly. Often it’s easier to use a number of JPanel
objects in a given display, each one with
its own LayoutManager
. Try breaking down
the problem: place related components in their own JPanel
and then arrange the panels in the
container. When that becomes unwieldy, use a constraint-based layout manager
such as GridBagLayout
or SpringLayout
, which we’ll discuss later in this
chapter.
Get Learning Java, 4th Edition now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.