Professional Documents
Culture Documents
Trail: Creating A GUI With JFC/Swing Lesson: Laying Out Components Within A Container
Trail: Creating A GUI With JFC/Swing Lesson: Laying Out Components Within A Container
Note: This lesson covers writing layout code by hand, which can be challenging. If you are not
interested in learning all the details of layout management, you might prefer to use the
GroupLayout layout manager combined with a builder tool to lay out your GUI. One such
builder tool is the NetBeans IDE. Otherwise, if you want to code by hand and do not want to use
GroupLayout, then GridBagLayout is recommended as the next most flexible and powerful
layout manager.
This section discusses some of the common tasks related to using layout managers:
As a rule, the only containers whose layout managers you need to worry about are JPanels and
content panes. Each JPanel object is initialized to use a FlowLayout, unless you specify
differently when creating the JPanel. Content panes use BorderLayout by default. If you do not
like the default layout manager that a panel or content pane uses, you are free to change it to a
different one. However, unless you are using JToolBar, the FlowLayout and BorderLayout
managers are only useful for prototyping. Any real application will need to reset the layout
manager. Again, you should use an appropriate tool to do this, rather than coding the manager by
hand.
You can set a panel's layout manager using the JPanel constructor. For example:
Although we strongly recommend that you use layout managers, you can perform layout without
them. By setting a container's layout property to null, you make the container use no layout
manager. With this strategy, called absolute positioning, you must specify the size and position
of every component within that container. One drawback of absolute positioning is that it does
not adjust well when the top-level container is resized. It also does not adjust well to differences
between users and systems, such as different font sizes and locales.
When you add components to a panel or content pane, the arguments you specify to the add
method depend on the layout manager that the panel or content pane is using. In fact, some
layout managers do not even require you to add the component explicitly; for example,
GroupLayout. For example, BorderLayout requires that you specify the area to which the
component should be added (using one of the constants defined in BorderLayout) using code
like this:
pane.add(aComponent, BorderLayout.PAGE_START);
The how-to section for each layout manager has details on what, if any, arguments you need to
specify to the add method. Some layout managers, such as GridBagLayout and SpringLayout,
require elaborate setup procedures. Many layout managers, however, simply place components
based on the order they were added to their container.
Swing containers other than JPanel and content panes generally provide API that you should use
instead of the add method. For example, instead of adding a component directly to a scroll pane
(or, actually, to its viewport), you either specify the component in the JScrollPane constructor
or use setViewportView. Because of specialized API like this, you do not need to know which
layout manager (if any) many Swing containers use. (For the curious: scroll panes happen to use
a layout manager named ScrollPaneLayout.)
For information about how to add components to a specific container, see the how-to page for
the container. You can find the component how-to pages using How to Use Various
Components.
Sometimes you need to customize the size hints that a component provides to its container's
layout manager, so that the component will be laid out well. You can do this by specifying one or
more of the minimum, preferred, and maximum sizes of the component. You can invoke the
component's methods for setting size hints — setMinimumSize, setPreferredSize, and
setMaximumSize. Or you can create a subclass of the component that overrides the appropriate
getter methods — getMinimumSize, getPreferredSize, and getMaximumSize. Here is an
example of making a component's maximum size unlimited:
component.setMaximumSize(new Dimension(Integer.MAX_VALUE,
Integer.MAX_VALUE));
Many layout managers do not pay attention to a component's requested maximum size. However,
BoxLayout and SpringLayout do. Furthermore, GroupLayout provides the ability to set the
minimum, preferred or maximum size explicitly, without touching the component.
Besides providing size hints, you can also provide alignment hints. For example, you can specify
that the top edges of two components should be aligned. You set alignment hints either by
invoking the component's setAlignmentX and setAlignmentY methods, or by overriding the
component's getAlignmentX and getAlignmentY methods. Although most layout managers
ignore alignment hints, BoxLayout honors them. You can find examples of setting the alignment
in How to Use BoxLayout.
Three factors influence the amount of space between visible components in a container:
The layout manager
Some layout managers automatically put
space between components; others do not.
Some let you specify the amount of space
between components. See the how-to page
for each layout manager for information
about spacing support.
Invisible components
You can create lightweight components that
perform no painting, but that can take up
space in the GUI. Often, you use invisible
components in containers controlled by
BoxLayout. See How to Use BoxLayout for
examples of using invisible components.
Empty borders
No matter what the layout manager, you can
affect the apparent amount of space between
components by adding empty borders to
components. The best candidates for empty
borders are components that typically have
no default border, such as panels and labels.
Some other components might not work
well with borders in some look-and-feel
implementations, because of the way their
painting code is implemented. For
information about borders, see How to Use
Borders.
This website is written in English, with text that runs from left to right, and then top to bottom.
However, many other languages have different orientations. The componentOrientation
property provides a way of indicating that a particular component should use something different
from the default left-to-right, top-to-bottom orientation. In a component such as a radio button,
the orientation might be used as a hint that the look and feel should switch the locations of the
icon and text in the button. In a container, the orientation is used as a hint to the layout manager.
To set a container's orientation, you can use either the Component-defined method
setComponentOrientation or, to set the orientation on the container's children as well,
applyComponentOrientation. The argument to either method can be a constant such as
ComponentOrientation.RIGHT_TO_LEFT, or it can be a call to the ComponentOrientation
method getOrientation(Locale). For example, the following code causes all JComponents to
be initialized with an Arabic-language locale, and then sets the orientation of the content pane
and all components inside it accordingly:
JComponent.setDefaultLocale(new Locale("ar"));
JFrame frame = new JFrame();
...
Container contentPane = frame.getContentPane();
contentPane.applyComponentOrientation(
ComponentOrientation.getOrientation(
contentPane.getLocale()));
Here are two pictures showing how FlowLayout lays out components in containers that are
exactly the same, except for their orientation.
Default orientation (left-to-right)
Right-to-left orientation
The standard layout managers that support component orientation are FlowLayout,
BorderLayout, BoxLayout, GridBagLayout, and GridLayout.
Note: Care must be taken that the component orientation is applied to renderers, editors and any
other components unreachable through normal traversal of the containment hierarchy.
Layout managers have different strengths and weaknesses. This section discusses some common
layout scenarios and which layout managers might work for each scenario. However, once again,
it is strongly recommended that you use a builder tool to create your layout managers, such as
the NetBeans IDE 5.5 Matisse GUI builder, rather than coding managers by hand. The scenarios
listed below are given for information purposes, in case you are curious about which type of
manager is used in different situations, or in case you absolutely must code your manager
manually.
If none of the layout managers we discuss is right for your situation and you cannot use a builder
tool, feel free to use other layout managers that you may write or find. Also keep in mind that
flexible layout managers such as GridBagLayout and SpringLayout can fulfill many layout
needs.
Scenario: You need to display a few components in a compact row at their natural size.
Consider using a JPanel to group the
components and using either the JPanel's
default FlowLayout manager or the
BoxLayout manager. SpringLayout is also
good for this.
Scenario: You need to display a few components of the same size in rows and columns.
GridLayout is perfect for this.
Scenario: You need to display a few components in a row or column, possibly with varying
amounts of space between them, custom alignment, or custom component sizes.
BoxLayout is perfect for this.
Scenario: You need to display aligned columns, as in a form-like interface where a column of
labels is used to describe text fields in an adjacent column.
SpringLayout is a natural choice for this.
The SpringUtilities class used by several
Tutorial examples defines a
makeCompactGrid method that lets you
easily align multiple rows and columns of
components.
Scenario: You have a complex layout with many components.
Consider either using a very flexible layout
manager such as GridBagLayout or
SpringLayout, or grouping the components
into one or more JPanels to simplify layout.
If you take the latter approach, each JPanel
might use a different layout manager.
Note: This lesson covers writing layout code by hand, which can be challenging. If you are not
interested in learning all the details of layout management, you might prefer to use the
GroupLayout layout manager combined with a builder tool to lay out your GUI. One such
builder tool is the NetBeans IDE. Otherwise, if you want to code by hand and do not want to use
GroupLayout, then GridBagLayout is recommended as the next most flexible and powerful
layout manager.
The end result is that to determine the best size for the container, the system determines the sizes
of the containers at the bottom of the containment hierarchy. These sizes then percolate up the
containment hierarchy, eventually determining the container's total size.
If the size of a component changes, for example following a change of font, the component must
be resized and repainted by calling the revalidate and repaint methods on that component.
Both revalidate and repaint are thread-safe — you need not invoke them from the event-
dispatching thread.
When you invoke revalidate on a component, a request is passed up the containment hierarchy
until it encounters a container, such as a scroll pane or top-level container, that should not be
affected by the component's resizing. (This is determined by calling the container's
isValidateRoot method.) The container is then laid out, which has the effect of adjusting the
revalidated component's size and the size of all affected components.
In many types of look and feel, panels are opaque by default. Opaque panels work well as
content panes and can help with painting efficiently, as described in Using Top-Level
Containers. You can change a panel's transparency by invoking the setOpaque method. A
transparent panel draws no background, so that any components underneath show through.
An Example
The following picture shows a colored version of the Converter application, which is discussed
in more detail in Using Models.
As the Converter example demonstrates, panels are useful for grouping components,
simplifying component layout, and putting borders around groups of components. The rest of
this section gives hints on grouping and laying out components. For information about using
borders, see How to Use Borders.
Like other containers, a panel uses a layout manager to position and size its components. By
default, a panel's layout manager is an instance of FlowLayout, which places the panel's contents
in a row. You can easily make a panel use any other layout manager by invoking the setLayout
method or by specifying a layout manager when creating the panel. The latter approach is
preferable for performance reasons, since it avoids the unnecessary creation of a FlowLayout
object.
Here is an example of how to set the layout manager when creating the panel.
Adding Components
When you add components to a panel, you use the add method. Exactly which arguments you
specify to the add method depend on which layout manager the panel uses. When the layout
manager is FlowLayout, BoxLayout, GridLayout, or SpringLayout, you will typically use the
one-argument add method, like this:
aFlowPanel.add(aComponent);
aFlowPanel.add(anotherComponent);
When the layout manager is BorderLayout, you need to provide an argument specifying the
added component's position within the panel. For example:
aBorderPanel.add(aComponent, BorderLayout.CENTER);
aBorderPanel.add(anotherComponent, BorderLayout.PAGE_END);
With GridBagLayout you can use either add method, but you must somehow specify grid bag
constraints for each component.
For information about choosing and using the standard layout managers, see Using Layout
Managers.
The API in the JPanel class itself is minimal. The methods you are most likely to invoke on a
JPanel object are those it inherits from its superclasses — JComponent, Container, and
Component. The following tables list the API you are most likely to use, with the exception of
methods related to borders and layout hints. For more information about the API that all
JComponent objects can use, see The JComponent Class.
Creating a JPanel
Managing a Container's Components
Setting or Getting the Layout Manager
Creating a JPanel
Constructor Purpose
Creates a panel. The LayoutManager parameter provides a layout
JPanel()
manager for the new panel. By default, a panel uses a FlowLayout to lay
JPanel(LayoutManager)
out its components.
Managing a Container's Components
Method Purpose
void add(Component) Adds the specified component to the panel. When present, the int
void add(Component, int) parameter is the index of the component within the container. By
void add(Component,
default, the first component added is at index 0, the second is at index
Object)
1, and so on. The Object parameter is layout manager dependent and
void add(Component,
typically provides information to the layout manager regarding
Object, int)
positioning and other layout constraints for the added component. The
void add(String,
String parameter is similar to the Object parameter.
Component)
int getComponentCount() Gets the number of components in this panel.
Component
getComponent(int)
Component
getComponentAt(int, int) Gets the specified component or components. You can get a
Component component based on its index or x, y position.
getComponentAt(Point)
Component[]
getComponents()
void remove(Component)
void remove(int) Removes the specified component(s).
void removeAll()
Setting or Getting the Layout Manager
Method Purpose
void Sets or gets the layout manager for this panel. The layout manager
setLayout(LayoutManager) is responsible for positioning the panel's components within the
LayoutManager getLayout() panel's bounds according to some philosophy.
Many examples contained in this lesson use JPanel objects. The following table lists a few.
Where
Example Notes
Described
Uses five panels, four of which use BoxLayout and one of which
Converter This section uses GridLayout. The panels use borders and, as necessary, size
and alignment hints to affect layout.
ListDemo
How to Use Uses a panel, with its default FlowLayout manager, to center
Lists three components in a row.
ToolBarDemo
How to Use Uses a panel as a content pane. The panel contains three
Tool Bars components, laid out by BorderLayout.
BorderDemo
How to Use Contains many panels that have various kinds of borders.
Borders Several panels use BoxLayout.
How to Use
BoxLayoutDemo Illustrates the use of a panel with Swing's BoxLayout manager.
BoxLayout
Here is a picture of a demo that opens a small window and prompts the user to type in a
password.
Click the Launch button to run PasswordDemo using Java™ Web Start (download JDK 6).
Alternatively, to compile and run the example yourself, consult the example index.
The password is "bugaboo". You can find the entire code for this program in
PasswordDemo.java. Here is the code that creates and sets up the password field:
passwordField = new JPasswordField(10);
passwordField.setActionCommand(OK);
passwordField.addActionListener(this);
The argument passed into the JPasswordField constructor indicates the preferred size of the
field, which is at least 10 columns wide in this case. By default a password field displays a dot
for each character typed. If you want to change the echo character, call the setEchoChar
method. The code then adds an action listener to the password field, which checks the value
typed in by the user. Here is the implementation of the action listener's actionPerformed
method:
public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand();
passwordField.selectAll();
resetFocus();
} else ...//handle the Help button...
}
Security note: Although the JPasswordField class inherits the getText method, you should
use the getPassword method instead. Not only is getText less secure, but in the future it might
return the visible string (for example, "******") instead of the typed string.
To further enhance security, once you are finished with the character array returned by the
getPassword method, you should set each of its elements to zero. The preceding code snippet
shows how to do this.
A program that uses a password field typically validates the password before completing any
actions that require the password. This program calls a private method, isPasswordCorrect,
that compares the value returned by the getPassword method to a value stored in a character
array. Here is its code:
if (input.length != correctPassword.length) {
isCorrect = false;
} else {
isCorrect = Arrays.equals (input, correctPassword);
}
return isCorrect;
}
The following tables list the commonly used JPasswordField constructors and methods. For
information on the API that password fields inherit, see How to Use Text Fields.
PasswordDemo is the Tutorial's only example that uses a JPasswordField object. However, the
Tutorial has many examples that use JTextField objects, whose API is inherited by
JPasswordField. See Examples That Use Text Fields for further information.