Layout Managers


The java.awt package contains a very useful class called Container. Generally, you don't instantiate this class directly. Rather, you instantiate its various subclasses, which include Frame. All containers have the following properties:

  • They are rectangular.

  • They can contain other components, including other containers.

  • They use layout managers to determine the locations and positions of the components they contain.

The great thing about layout managers is that you don't have to think about the details of component layout. Each layout manager class imposes a different layout policy on the container it manages. All you have to do is become familiar with the various layout policies available to you. The layout manager will take care of the details.

To change a container's layout policy, you construct an instance of the desired layout manager class. Then you call the container's setLayout() method, passing in the layout manager. All the code examples in this chapter have used frames, and the layout manager for a frame is something called a border layout manager. The border layout policy is completely inappropriate to what we wanted to do, but a different manager, the flow layout manager, is perfect.

This explains why every example constructed an instance of FlowLayout and then passed the instance into a setLayout() call. Usually this was done in a single line:

setLayout(new FlowLayout());

To understand layout policies, and therefore to understand why we used flow layout so extensively, you have to understand the concept of preferred size. Every component has a preferred size, which a layout manager can either honor or ignore. For components that have text, such as buttons and checkboxes, the preferred size is just large enough to accommodate the component's text. For components without text, the preferred size is arbitrary, which usually is not very good. The preferred size of a scrollbar, for example, is 15x50 pixels.

The Flow Layout Manager

The flow layout manager always honors the preferred size of its container's components. Every component in every figure in this chapter has been its preferred size, because every frame has used a flow layout manager.

When a container uses a flow layout manager, its contained components appear from left to right in the order they were added to the container. There is a gap of five pixels between adjacent components. The cluster of components appears at the top of the container and is centered horizontally. (Horizontal centering is the default. There are other options. See Exercise 6.)

The following code creates three components and uses a flow layout manager to position them in a frame:

import java.awt.*; class SimpleFlow extends Frame {   public SimpleFlow()   {     setLayout(new FlowLayout());     add(new Label("ABCDEFGH"));     add(new Button("Hello"));     Font f = new Font("SansSerif", Font.BOLD, 24);     Button btn = new Button("Goodbye");     btn.setFont(f);     add(btn);     setSize(300, 200);   }   public static void main(String[] args)   {     (new SimpleFlow()).setVisible(true);   } } 

Figure 15.21 shows the code's GUI. Notice how the components are spaced evenly and centered horizontally.


Figure 15.21: Flow layout manager

Figure 15.22 shows the same GUI, after the frame has been made wider. The cluster is still centered.

click to expand
Figure 15.22: Wider

And Figure 15.23 shows the GUI one last time. Now the frame is too narrow to fit all three components. When this happens, the flow layout manager makes another row. If the frame were even narrower, there would be yet another row.


Figure 15.23: Narrower

You can configure flow layout managers to place their clusters at the left or right of their containers, rather than in the center. You do this by passing an int into the FlowLayout constructor. If the int is FlowLayout.LEFT, the cluster will appear at the left; if the int is FlowLayout.RIGHT, the cluster will appear at the right. Figure 15.24 shows the three-component GUI of the current example, with the setLayout() line changed to

setLayout(new FlowLayout(FlowLayout.LEFT)); 

click to expand
Figure 15.24: Left-aligned

The Flow Lab animated illustration lets you experiment with components that are managed by a flow layout manager. To start the application, type java flow.FlowLab. Figure 15.25 shows the initial screen.

click to expand
Figure 15.25: Flow Lab

Flow Lab lets you select a left-, center-, or right-aligning layout manager. You can add buttons, checkboxes, text fields, and labels. Experiment with Flow Lab until you have a good feel for how the layout manager arranges its components. Select left alignment. Add components of a uniform size until the top row is full and a second row is created. How many components are in the top row? Does the number of components in the top row change when you select center or right alignment?

Notice that your selection of layout alignment affects only the main region of the display; the two control panels at the top of the display are not affected. It seems the layout manager you selected is only responsible for part, not all, of the frame. You will see how this is done a little later, in the "Panels" section. But first you have another layout manager to learn about.

The Border Layout Manager

The border layout policy is bizarre at first glance. It only makes sense after you learn what it's good for. So if your reaction to the next few paragraphs is, "This is weird," congratulations. You're right on track.

A border layout manager partially honors and partially ignores the preferred size of its container's components. A preferred size consists of two dimensions: width and height. A border layout manager might ignore one of a component's preferred dimensions while honoring the other. Or both preferred dimensions might be ignored. They are never both honored.

A container that uses a border layout manager may not contain more than five components. The layout manager divides the container into five regions, named North, South, East, West, and Center. Each region may be occupied by zero or one components.

The component in the North region is placed at the top of its container. The component's height is its preferred height; its width is the entire width of the container. Figure 15.26 shows a horizontal scrollbar in the North region of a frame.


Figure 15.26: Scrollbar at North

Here is the code that produced Figure 15.26:

 1. import java.awt.*;  2.  3. class BarAtNorth extends Frame  4. {  5.   public BarAtNorth()  6.   {  7.     Scrollbar bar=new Scrollbar(Scrollbar.HORIZONTAL);  8.     add(bar, "North");  9.     setSize(200, 100); 10.   } 11. 12.   public static void main(String[] args) 13.   { 14.     (new BarAtNorth()).setVisible(true); 15.   } 16. }

The constructor does not call setLayout(), because you want to use a border layout manager, which is the default for a frame. In other words, the right kind of layout manager is already there.

Look at line 8. When you add components to a container that uses a border layout manager, you have to pass a second argument to the add() method. This is a string that must be North, South, East, West, or Center.

The component at South is attached to the bottom of the container. Otherwise, it is treated like the component at North. Its preferred height is honored, and its width is the entire width of the container.

Figure 15.27 shows a frame with a horizontal scrollbar at North and a text field at South.


Figure 15.27: North and South occupied

The code that produced Figure 15.27 is almost identical to the code that produced Figure 15.26. The difference is that this code has the following lines before the setSize() call:

TextField tf = new TextField("Hello"); add(tf, "South");

As you might guess, the components at East and West are attached to the right and left edges of their container, respectively. Their preferred widths are honored. Their heights are the height of the container... almost. They extend all the way up to the top of the container, unless there is a component at North. In that case, they only extend to the bottom of the North component. Similarly, if there is no component at South, the East and West components can extend all the way down to the bottom of the container. But if there is a component at South, the East and West components extend down just to the top of the South component.

There are many combinations of the presence or absence of North or South or East or West components, but Figure 15.28 should make things clear. In the figure, there are components at North, East, and West.


Figure 15.28: North, East, and West occupied

There is no component at South, so the two buttons extend down all the way to the bottom of the container. Since the scrollbar occupies North, the buttons do not extend all the way to the top of the container. They defer to North, extending up to the bottom of the scrollbar. Notice how the buttons have different preferred widths as a result of their different fonts.

So much for North, South, East, and West. The component at Center, if there is one, occupies all the territory that is left over after all other components have been sized and positioned. The white region in Figure 15.28 is the area where there are no components, so the white background of the frame is visible. If the frame had a component at Center, that component would fill the white region exactly. In Figure 15.29, a text area has been added at Center.

click to expand
Figure 15.29: North, East, West, and Center occupied

Here is the code that produced Figure 15.29:

 1. import java.awt.*;  2.  3. class NEAndW extends Frame  4. {  5.  6.   public NEAndW()  7.   {  8.     Scrollbar bar=new Scrollbar(Scrollbar.HORIZONTAL);  9.     add(bar, "North"); 10.     Button btn = new Button("Me West"); 11.     add(btn, "West"); 12.     btn = new Button("Me East"); 13.     btn.setFont(new Font("Serif", Font.PLAIN, 50)); 14.     add(btn, "East"); 15.     TextArea ta = new TextArea(); 16.     add(ta, "Center"); 17.     setSize(600, 400); 18.   } 19. 20.   public static void main(String[] args) 21.   { 22.     (new NEAndW()).setVisible(true); 23.   } 24. }

Notice the TextArea constructor on line 15. This version is different from the one you were introduced to, where you passed in arguments to specify the number of rows and columns. The no-args version used here is for situations where the text area's size will be determined by the layout manager, so there is no need for you to specify a size.

Panels

Panels are components that divide containers into regions that are smaller and more manageable. The java.awt.Panel class extends java.awt.Container, so every panel has its own layout manager. You can think of panels as rectangular components that can contain other components, including panels. These in turn can include panels, and so on, so it is possible to create a complex layered hierarchical GUI.

Figure 15.30 shows a frame whose South component is a panel containing three buttons. The panel's only other component is a text area at Center.

click to expand
Figure 15.30: A panel in a frame

Here is the code that created Figure 15.30:

 1. import java.awt.*;  2.  3. class PanelInFrame extends Frame  4. {  5.   public PanelInFrame()  6.   {  7.     Panel pan = new Panel(); 8.     pan.add(new Button("OK"));  9.     pan.add(new Button("Cancel")); 10.     pan.add(new Button("Help")); 11.     add(pan, "South"); 12.     TextArea ta = new TextArea(); 13.     add(ta, "Center"); 14.     setSize(400, 250); 15.   } 16. 17.   public static void main(String[] args) 18.   { 19.     (new PanelInFrame()).setVisible(true); 20.   } 21. }

When you use panels, you make a lot of calls to the add() method of various containers. It's important to keep track of what is being added to what. On lines 8-10, the buttons are added to the panel. On line 11, the panel is added to the frame. On line 13, the text area is added to the frame.

The code has no setLayout() calls. The default layout manager for panels is flow. This is confusing, because the default manager for frames is border layout. You have to remember which container type defaults to which layout policy. But in practice, the defaults are usually what you want, so you don't often have to call setLayout().

The flow layout manager makes more sense when you know about panels. Most GUI-based applications consist of a frame that contains a control area and a work area. For example, all Web browsers have a control panel at the top of the display with buttons for going forward, back, home, and so on. Below the control panel is the Web page viewing area. Generally, at the bottom is a status message. When you enlarge the browser, you don't want more space for the controls or the status message; you want a bigger Web page viewing area. The same holds true for most word processors, painting programs, and indeed most programs in general. When the user resizes, it is the main work area below the control area that should do most of the growing.

This is exactly the behavior that you get when you use a frame with a panel at North and some kind of work area at Center. The panel is attached to the top of the frame, and is as wide as the frame. It is a tall as it needs to be to accommodate the components it contains. (That's how the preferred height of a panel is defined.) When the frame becomes wider or narrower, the panel's components are repositioned automatically. When the frame becomes higher or shorter, it is the work area and not the panel that grows or shrinks. At the end of the next chapter, after you have learned how to detect input activity from components, you will work through a final project whose GUI consists of a panel at North and a work area at South.

The Layout Lab animated illustration lets you experiment with hierarchical combinations of containers, layout managers, and components. Layout Lab is designed to let you play with layout ideas without going through the effort of writing code to implement your ideas. To start the program, type java layout.LayoutLab. You will see the display shown in Figure 15.31.

click to expand
Figure 15.31: Layout lab

Initially, the display displays a representation of a frame named Frame0. If you want to change the frame's properties, including its layout manager, click on the Frame0 button. You will see the dialog box shown in Figure 15.32.

click to expand
Figure 15.32: Layout lab's frame editing dialog

Make sure the frame's layout manager is set to Border. Then dismiss the edit dialog by clicking its Apply button. Now add a component to the frame. Click on the + button. You will see a small dialog that lets you choose a button, a scrollbar, a checkbox, a text field, or a panel. Select Panel, and then click the Apply button. The main window will now look like Figure 15.33.

click to expand
Figure 15.33: Layout Lab with an added panel

Now click on the Pan0 button to edit the properties of the new panel. Since the panel is inside the frame, which uses a border layout manager, one of the panel's properties is its region within the frame (North, South, East, West, or Center). Select South and then click the Apply button.

Now it's time to put a few buttons in the panel. In the main screen, click on the + button. When the little component-chooser dialog appears, select Button and then click Apply. Now the main window will look like Figure 15.34.

click to expand
Figure 15.34: A button in a panel in a frame

Edit the button by clicking on Btn0 in the main window. You will see a dialog box that lets you edit the button's location, position, font, and text. Set both X and Y to 500. Set the font to something conspicuously non-default, like SansSerif 36-point bold italic. Set the label to whatever text you like, and click the Apply button.

Now you have created a description of a slightly complicated hierarchical GUI: a button in a panel at the South of a frame. To see what the GUI really looks like, click the Make It So button. You will see a frame that looks like Figure 15.35.


Figure 15.35: Layout Lab makes it so

The button is definitely not 500x500 pixels in size. Is the button's property dialog broken? No. Remember that the panel is using a flow layout manager, which honors the button's preferred size. As you can see in Figure 15.34, the button's preferred size is much smaller than 500x500. In fact, it is just large enough to accommodate the button's text.

Now experiment with layout lab. Try adding more buttons, or other kinds of components, to the panel. Add a panel to the frame's Center. Choose a layout manager for the new panel, add components, including a panel, and add components to that. If you want to get rid of a component, click on its X button in the main display. (If the component is a panel, all its contents will be deleted as well. You aren't allowed to delete the frame.) You can click the ^ and v buttons to change the ordering of components in their container.

Play with Layout Lab until you feel comfortable with the idea of components inside a panel that is inside a panel that is inside a frame.

Other Layout Managers

Before we leave the topic of layout managers, it is appropriate to mention that there are other options besides flow and border. The java.awt package provides three other managers, called CardLayout, GridLayout, and GridBagLayout. All three are beyond the scope of an introductory book, but you should know that they exist so that you can investigate them if you ever decide you need them.

CardLayout allows only one component to be seen at any time. GridLayout organizes its container into a grid of rows and columns; each component occupies a single grid location. GridBagLayout also creates rows and columns, but it provides many more options than GridLayout does.

Several other layout managers (BoxLayout, OverlayLayout, and SpringLayout) are part of the javax.swing package. Swing is an alternative to the AWT toolkit. Its components are much more sophisticated than those of AWT.

You can create your own layout manager class. To do this, you implement the java.awt.LayoutManager interface. It isn't especially hard once you get the hang of it. The interface only has five methods, and several of them are trivial. Many of this book's animated illustrations display Java source code that is mostly text, with a few scattered text fields or choices that allow you to configure the source code. The data chain lab in Chapter 13 did this. This kind of layout cannot be achieved with any of the standard layout managers, so a new layout manager class was created.

There is one last layout manager option, and it is offered with caution. You can call setLayout(null) to operate with no layout manager at all. Then it is your responsibility to set the size and location of every component. You do this by calling the following methods on the components:

void setLocation(int x, int y) Sets the component's location (upper-left corner) to (x, y).

void setSize(int width, int height) Sets the component's size to width-by-height.

void setBounds(int x, int y, int width, int height) Sets the component's location to (x, y) and its size to width-by-height.

The following code uses no layout manager. It creates a 300-by-300 button and positions it at (40, 40):

import java.awt.*; class NullLayout extends Frame {   public NullLayout()   {     setLayout(null);     Button btn = new Button("Cancel");     btn.setSize(300, 300);     btn.setLocation(40, 40);     add(btn);     setSize(400, 400);   }   public static void main(String[] args)   {     (new NullLayout()).setVisible(true);   } }

Figure 15.36 shows the GUI.

click to expand
Figure 15.36: No layout manager

The Layout Lab animated illustration lets you set any container's layout manager to None. Do this to the frame, and add two buttons labeled OK and Cancel. Edit each button's position and size until you like what you see. Get a feel for the ease or difficulty of this task.

The no-layout-manager strategy should be used with caution. As Figure 15.36 shows, it is easy to create a GUI with components of inappropriate size or location. Moreover, when your container has more than a very few components, it is unlikely to look good when the user resizes it.




Ground-Up Java
Ground-Up Java
ISBN: 0782141900
EAN: 2147483647
Year: 2005
Pages: 157
Authors: Philip Heller

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net