Lecture 10
Layout
Managers
How
do you control the arrangement of components in Java so that your GUI looks as you
wish it to look? Read
on for an explanation of three common layout managers.
Introduction
Creating
and Setting Layout Managers
Creating
a Layout Manager
Setting
a Containers Layout
Quick
Coding Example
FlowLayout
Creating
a FlowLayout
BorderLayout
Creating
a BorderLayout
GridLayout
Creating
a GridLayout
Layouts
and Containers within Containers
Introduction
Layout managers are
used to arrange GUI components in a container. It is possible to position
components in a container using coordinates and absolute positioning but think
how tedious that would be. It is far easier to use the basic layout
capabilities provided by layout managers.
Java comes with a few
different layout managers. We shall look at three
commonly used layout managers:-
|
Arranges
components sequentially in rows in the order they were added to the
container. This is the default layout for panels
|
|
Arranges
components in regions - North, South, East, West and Center. This is the
default layout for applets
|
|
Places
components in cells arranged into rows and columns.
|
You should note that
the default layout manger for frames and applets is BorderLayout
and the default for panels is FlowLayout . However, you can
set the layout manager for every container in your GUI as you choose.
Every container you have in your GUI can be set to have a different layout
manager if desired.
The applet below shows
you the different layout managers in action. Watch how the arrangement of
the five buttons changes as you select a different layout manager from the menu.
~~~Applet~~~
There are two
things you have to do to specify a layout for a container.
-
Create an
instance of a LayoutManager (using the new
keyword)
-
Set the layout of
the container (using the setLayout method)
Let's get started.
Creating
and Setting Layout Managers
Before
examining each layout manager in detail, let's get a rough idea of how to
create a layout manager instance and how to set a containers layout
manager. Then to get the feel of creating and setting layout manager objects
we will finish this section with some practice coding.
Creating
a Layout Manager
To create a layout manager object
we use the new keyword and use a valid layout manager constructor :-
//
creates an instance of a FlowLayout
FlowLayout
myFlowLayout = new FlowLayout();
//
creates an instance of a BorderLayout
BorderLayout
myBorderLayout = new BorderLayout();
//
creates an instance of a GridLayout
GridLayout
myFlowLayout = new GridLayout(3,3);
That wasn't so bad
was it. I now have three different layout manager objects. In
each case, creating them is similar. The GridLayout
constructor is slightly different. The 3,3 values placed
in the parentheses indicate I want 3 rows and 3
columns, giving six cells for placing components.
Setting
a Containers Layout
To
set the layout manager of any container all you do is use the setLayout method
and specify a layout manager object:-
//
This is not real code
someContainer.setLayout(some
layout manager object);
So there are two
things we need to specify to use the setLayout method.
The container we wish to set the layout of and a layout manager object.
Well the first part
is easy enough since we know about containers, but let's have a few
examples:-
//
This is still not real code
//
sets the layout manager of a content pane
getContentPane().setLayout(some
layout manager object);
//
This is still not real code
//
create a panel
JPanel
myPanel = new JPanel();
//
sets the layout manager of the panel
myPanel.setLayout
(some layout manager object);
Let's specify a layout manager
object now:-
//
This is real code
//
creates an instance of a FlowLayout
FlowLayout
myFlowLayout = new FlowLayout();
//
sets the layout manager of a content pane
getContentPane().setLayout(myFlowLayout);
I
could use one line instead of two for creating and setting a layout:-
//
creates and sets the layout manager of a content pane
getContentPane().setLayout(
new FlowLayout() );
Notice
how I created the new layout manager instance on the fly, inside the
parentheses of the setLayout method. Of course this means
I haven't got a variable that references my layout manager object, so I
cannot refer to it again later on in my code.
Now
for a bit of coding practice:
Quick
Coding Example
Let's
play with some layout managers.
This
code creates an applet with five buttons, adds them to the content pane of an
applet and sets the layout of the content pane to one of the created layout
manager objects:-
import javax.swing.*;
import java.awt.*;
public class LayoutTest extends JApplet {
public void init() {
//create a variable that references
//the content pane of the applet
Container appletContainer = getContentPane();
// creates an instance of a FlowLayout
FlowLayout myFlowLayout = new FlowLayout();
// creates an instance of a BorderLayout
BorderLayout myBorderLayout = new BorderLayout();
// creates an instance of a GridLayout
GridLayout myGridLayout = new GridLayout(3,3);
// set the layout of the applet's content pane
appletContainer.setLayout( myFlowLayout );
// create some buttons
JButton button1 = new JButton("Button1");
JButton button2 = new JButton(" Button2");
JButton button3 = new JButton(" Button3");
JButton button4 = new JButton(" Button4");
JButton button5 = new JButton(" Button5");
// add the buttons to the applet
appletContainer.add(button1);
appletContainer.add(button2);
appletContainer.add(button3);
appletContainer.add(button4);
appletContainer.add(button5);
}
}
|
The
layout could be set to one of three possible layouts since I created three
different layout manager objects - myFlowLayout , myBorderLayout
and myGridLayout . The setLayout method above
actually used the myFlowLayout object.
What
happens if you change the line of code:-
appletContainer.setLayout( myFlowLayout );
to
appletContainer.setLayout( myGridLayout );
or
appletContainer.setLayout( myBorderLayout
);
or
you comment out the setLayout line
// appletContainer.setLayout( myBorderLayout
);
Some points to
consider:-
-
The
default layout manager for the content pane of an applet is BorderLayout .
So specifying myBorderLayout doesn't actually change anything.
-
We
have seen before that adding more than one component to the content pane of
an applet doesn't show more than one of the components (the last added to
be exact). We shall see why later.
-
What happens to
the size and position of the components for each of the different layout
managers when you resize the applet window?
The following
sections look at each layout manager in more detail
FlowLayout
FlowLayout
arranges components in rows from left-to-right, top-to-bottom order. The
order of the components will be the same order that you add them to the
container.
FlowLayout
figures out how big the container is and positions of the components one by
one along a row until the next component will not fit, in which case
components are positioned on the next row, and so on. If the container size is changed
(e.g. when the user resizes the window), FlowLayout will recalculate new positions for all the components.
FlowLayout
places a component leaving it at the preferred size for that component (i.e.
kind of a default size).
Creating
a FlowLayout
There are
three constructors
to choose from when creating a FlowLayout object.
|
A
FlowLayout manager object is created that will center-align components and
space components 5 pixels apart.
|
|
A
FlowLayout manager object is created that will align components based on the
alignment you specify ( FlowLayout.LEFT,
FlowLayout.CENTER, FlowLayout.RIGHT)
and space components 5 pixels apart.
|
|
A
FlowLayout manager object is created that will align components based on the
alignment you specify ( FlowLayout.LEFT,
FlowLayout.CENTER, FlowLayout.RIGHT)
with the space between components specified by
hgap and vgap
|
As
you can see from the table, FlowLayout allows you to specify the
alignment of the components if you choose the second or third
constructor method. You can have left, center and right-aligned.
By default, components are center-aligned.
To
set the layout manager of a container all you do is use the setLayout method
and specify a layout manager object you have created:-
FlowLayout
aFlowLayout = new FlowLayout();
getContentPane().setLayout(aFlowLayout);
The
first line creates a FlowLayout object referenced by aFlowLayout.
The second line sets the layout of the content pane of the applet to aFlowLayout.
Components added to this applets
content pane would be arranged in rows, center-aligned and 5 pixels
apart.
I
could use one line of code instead of two for creating and setting a layout
manager:-
getContentPane().setLayout(new
FlowLayout());
All
this means is that I cannot reference the FlowLayout object
again since I created it on the fly inside the setLayout
method
Let's
try another example:-
FlowLayout
anotherFlowLayout = new FlowLayout (FlowLayout.LEFT,10,20);
getContentPane().setLayout(anotherFlowLayout);
The
first line creates a FlowLayout object referenced by anotherFlowLayout.
The second line sets the layout of the content pane of the applet to anotherFlowLayout.
Components added to this applets content pane would be arranged in rows, left-aligned and
spaced 10 pixels apart horizontally, 20 pixels apart vertically.
I
could use one line of code instead of two for creating and setting a layout
manager:-
getContentPane().setLayout(new
FlowLayout
(FlowLayout.LEFT,10,20));
Now try this code:-
import javax.swing.*;
import java.awt.*;
public class LayoutFlow extends JApplet {
public void init() {
//create a variable that references
//the content pane of the applet
Container appletContainer = getContentPane();
// set the layout to FlowLayout
appletContainer.setLayout( new FlowLayout() );
// creates five buttons
JButton button1 = new JButton("Button1");
JButton button2 = new JButton(" Button2");
JButton button3 = new JButton(" Button3");
// add the buttons to the applet's content pane
appletContainer.add(button1);
appletContainer.add(button2);
appletContainer.add(button3);
}
}
|
You should end up
with something that looks like this:-
~Try the activity~
Activity 10A |
1. Use
appletviewer to display your applet and resize the window until you
are familiar with how FlowLayout arranges the buttons
2.
As we can see, the default alignment of the components is
center-alignment. Amend the code above
so that the alignment of the components is left or right. Hint:
check out the creation constructors.
|
BorderLayout
BorderLayout
divides a container into five different regions: North, South, East, West, and Center.
The picture below shows five buttons, each one added to a different region.
You should note the
following:-
-
The
size of a component expands to fill the whole region. This is why the
buttons look an odd size.
-
Components
in the North and South region are stretched horizontally.
-
Components
in the East and West region are stretched vertically.
-
The
center area expands horizontally and vertically as needed.
Try changing the size of an applet window set with a BorderLayout.
You'll see that only the center region expands.
-
You can add at most one component to each
region of a BorderLayout. To put more than one component in a region, put them in a panel (with its own layout), and then add that
panel to a region.
-
You can
leave regions empty. You don't have to add a component to every
region. Any region left without a component will have a zero size and
the other regions will expand as necessary to fill the applet window.
-
The
center region is excellent for placing components like text areas since the
text area will expand with the region if the window is resized.
Creating
a BorderLayout
There are
two constructors
to choose from when creating a BorderLayout object.
|
A
BorderLayout manager object is created. There will be no spaces between
the regions
|
|
A
BorderLayout manager object is created, with the space between regions specified by hgap
and vgap
|
To
set the layout manager of a container all you do is use the setLayout method
and specify a layout manager object you have created:-
BorderLayout
aBorderLayout = new BorderLayout();
getContentPane().setLayout(aBorderLayout);
The
first line creates a BorderLayout object referenced by aBorderLayout.
The second line sets the layout of the content pane of the applet to aBorderLayout.
I
could use one line of code instead of two for creating and setting a layout
manager:-
getContentPane().setLayout(new
BorderLayout());
All
this means is that I cannot reference the BorderLayout object
again since I created it on the fly inside the setLayout
method.
Now
what happens if I create, compile and run the following code? You'll
see that it is not quite right.
import
javax.swing.*;
import java.awt.*;
public class LayoutBorder extends JApplet {
public void init() {
//create a variable that references
//the content pane of the applet
Container appletContainer = getContentPane();
// set the layout to BorderLayout
// the default for an applet is BorderLayout
//so this line is unnecessary really
appletContainer.setLayout( new BorderLayout() );
// creates five buttons
JButton northButton = new
JButton("North Button");
JButton southButton = new
JButton("South Button");
JButton eastButton = new
JButton("East Button");
JButton westButton = new
JButton("West Button");
JButton centerButton = new
JButton("Center Button");
// add the buttons to the applet content pane
appletContainer.add(northButton);
appletContainer.add(southButton);
appletContainer.add(eastButton);
appletContainer.add(westButton);
appletContainer.add(centerButton);
}
}
|
Well,
what's wrong? Only the last button added to the applet's content pane appears.
That's
because, unlike a FlowLayout where the layout manager knows it
has to place the components in rows, the BorderLayout manager has
to be told which region to place a component in.
By
default, if you don't specify a region, the component will be added to the center
region. Moreover, since only one component is allowed per region, if
you keep adding a component to the same region, it will just be placed over
any existing components.
So
how do we specify a region? We use an alternative add
method. Instead of the familiar add method...
//
This is not real code
//
adds a component to a container
somecontainer.add(some
component);
we
use this...
//
This is still not real code
//
adds a component to a container in a specified region
somecontainer.add(some
component, BorderLayout Region);
We
specify a container to add the component to as normal. We also specify the
component to add inside the parentheses as normal. However, we now
specify the BorderLayout region in which to place the
component. Regions can be specified using BorderLayout.NORTH,
BorderLayout.EAST, BorderLayout.SOUTH, BorderLayout.WEST, or
BorderLayout.CENTER.
Here
are a few examples:-
//
This is real code
//
adds the button to the north region of the container
appletContainer.add(northButton,
BorderLayout.NORTH);
//
adds the button to the south region of the container
appletContainer.add(northButton,
BorderLayout.SOUTH);
~Try the activity~
Activity 10B |
1. Amend the
LayoutBorder code above
so that each button is placed in a different region of the applet
container. It should end up looking similar to the picture
shown at the start of this section.
2. Use
appletviewer to display your applet and resize the window until you
are familiar with the expanding habits of each region.
|
GridLayout
Look at the picture
of buttons arranges in a GridLayout .
As we can see, this
layout manager takes a group of components and arranges them in cells,
drawn all the same. We just specify the number of rows and columns when
we create the GridLayout instance.
In the case above we
have 3 rows, 3 columns making 6
cells. One cell is empty because I only added five component to the
container.
If you resize a GridLayout
window the cells and contents resize to fit the new window.
Creating
a GridLayout
There are
two constructors
to choose from when creating a GridLayout object.
|
A
GridLayout manager object is
created with the specified number of rows and columns. There will be no spaces between
the cells
|
|
A
GridLayout manager object is
created with the specified number of rows and columns and the space between
cells specified by hgap
and
vgap.
|
To
set the layout manager of a container to a aGridLayout all you do is use the setLayout method
and specify a layout manager object. So:-
//
create a GridLayout instance with 3 rows and 3 columns
GridLayout
aGridLayout = new GridLayout(3,3);
//
set the layout of the applet container to aGridLayout
getContentPane().setLayout(aGridLayout);
The
first line creates a GridLayout object referenced by aGridLayout.
The second line sets the layout of the content pane of the applet to aGridLayout.
I
could use one line of code instead of two for creating and setting a layout
manager:-
getContentPane().setLayout(new
GridLayout(3,3));
All
this means is that I cannot reference the GridLayout object
again since I created it on the fly inside the setLayout
method.
Now
create, compile and run the following code:-
import
javax.swing.*;
import java.awt.*;
public class LayoutGrid extends JApplet {
public void init() {
//create a variable that references
//the content pane of the applet
Container appletContainer = getContentPane();
// set the layout to GridLayout
appletContainer.setLayout( new GridLayout(3,3) );
// creates five buttons
JButton button1 = new
JButton("Button1");
JButton button2 = new
JButton("Button2");
JButton button3 = new
JButton("Button3");
JButton button4 = new
JButton("Button4");
JButton button5 = new
JButton("Button5");
// add the buttons to the applet content pane
appletContainer.add(button1);
appletContainer.add(button2);
appletContainer.add(button3);
appletContainer.add(button4);
appletContainer.add(button5);
}
}
|
You
should get something similar to the picture shown at the beginning of this
section.
~Try the activity~
Activity 10C |
1. Amend the
LayoutGrid code above
so that the horizontal space between cells is 10 pixels and the
vertical space is 20 pixels.
2. Change
the text of one of the buttons to something like "This is a
really long button caption" and see what happens to the size of
the cells.
3. What
happens if you change the line:-
appletContainer.setLayout( new GridLayout(3,3) );
to
appletContainer.setLayout( new GridLayout(0,3) );
or
appletContainer.setLayout( new GridLayout(3,0) );
|
Layouts
and Containers within Containers
Have a look at the
picture below. Do you recall this applet from the JButton
tutorial? Which layout manager do you think I used?
Yes, I used a FlowLayout
. However, suppose none of the layout
managers quite arranges our GUI in the way we want. Examine the picture
below. Do you recall this applet from the JCheckBox
tutorial? How do you suppose I managed to arrange the components in
this way?
None of the three
layout managers would position the components in such a fashion.
It cannot be a BorderLayout
because the Snow checkbox would expand to fill the region and
cover the Cloud checkbox. It cannot be a GridLayout
because we don't have three equally sized cells. It cannot be a FlowLayout
because the two checkboxes are not arranged in a row.
Here is a
simplification of some of the code I used:-
//set
the applet's content pane to a flow layout
getContentPane().setLayout(new
FlowLayout());
//create two panels
JPanel aPane1 = new JPanel ();
JPanel aPane2 = new JPanel ();
// add
the panels to the content pane
// they
will be added in a flow layout
getContentPane().add( aPane1);
getContentPane().add(aPane2);
// change
the layout of the panels to grid layout
aPane1.setLayout(new GridLayout(2,1));
aPane2.setLayout(new GridLayout(1,1));
// add
the checkboxes to the first panel
// they
will be added in a grid type of arrangement
aPane1.add(cloudButton);
aPane1.add(snowButton);
// add
the image label to the second panel
aPane2.add(aLabel);
|
Yes,
I created two panels and added them to the content pane of the applet, after
changing the content pane from the default BorderLayout to FlowLayout .
This means that the panels are arranged in a row. Then I added the components into the panels in a grid arrangement. Try
creating a similar sort of applet. Don't forget, if you want spaces
between components then you should choose the appropriate constructors for the
layout managers.
What
about the picture of the applet shown below? Do you recall this applet from the
JComboBox
tutorial? How did I manage this
arrangement? I have a JLabel at the top, a JComboBox
just below and an image JLabel below this.
Perhaps it is a Flowlayout,
where the applet window width is not too wide so the layout manager has to
arrange the components in separate rows! No - the image JLabel
would be a smaller size (the exact size of the image).
Perhaps it is a GridLayout
with three rows. No - all the components would be resized in their
cells so they were exactly the same size as each other.
I confess to using
two panels again. The content pane of the applet was left to its default BorderLayout
and the first panel containing the JLabel and JComboBox
were added to the North region. The second panel containing the image
JLabel was added to the Center region .
Finally, what about
the applet shown in the picture below? You will also find this in the JComboBox
tutorial?
I bet you think its a
Flowlayout ? Only parts of it are in a Flowlayout .
The top label (the one with the 'Font Changer ' caption)
would not fit in with a Flowlayout would it?
The border around the four lower components separates them from the top
label.
I'm not going to tell
you how I did it. How would do it?
That is folks!!
Now try the Layout
Managers exercise
|