home | O'Reilly's CD bookshelfs | FreeBSD | Linux | Cisco | Cisco Exam  


Java AWT

Previous Chapter 7 Next
 

7. Layouts

This chapter expands upon the idea of a layout manager, which was mentioned briefly in the previous chapter. Every container has a LayoutManager that is responsible for positioning the component objects within it, regardless of the platform or the screen size. Layout managers eliminate the need to compute component placement on your own, which would be a losing proposition since the size required for any component depends on the platform on which it is displayed. Even for a simple layout, the code required to discover component sizes and compute absolute positions could be hundreds of lines, particularly if you concern yourself with what happens when the user resizes a window. A layout manager takes care of this for you. It asks each component in the layout how much space it requires, then arranges the components on the screen as best it can, based on the component sizes on the platform in use and the space available, resizing the components as needed.

To find out how much space a component needs, a layout manager calls the component's getMinimumSize() and getPreferredSize() methods. (  Java 1.1 also has a getMaximumSize() method; the existing layout managers don't take advantage of it.) These methods report the minimum space that a component requires to be displayed correctly and the optimal size at which it looks best. Thus, each component must know its space requirements; the layout manager uses these to arrange the screen; and your Java program never has to worry about platform-dependent positioning.

The java.awt package provides five layout managers: FlowLayout, BorderLayout, GridLayout, CardLayout, and GridBagLayout. Four additional layouts are provided in the sun.awt package: HorizBagLayout, VerticalBagLayout, OrientableFlowLayout, and VariableGridLayout. OrientableFlowLayout is new to Java 1.1. Of the 1.0 layouts, all are available in the JDK and Internet Explorer. The VariableGridLayout is also available with Netscape Navigator. This chapter discusses all of them, along with the LayoutManager and LayoutManager2 interfaces; we'll pay particular attention to how each layout manager computes positions for its components. We will also discuss how to combine layouts to generate more complex screens and how to create your own LayoutManager for special situations.

7.1 The LayoutManager Interface

The LayoutManager interface defines the responsibilities of something that wants to lay out Components within a Container. It is the LayoutManager's duty to determine the position and size of each component within the Container. You will never directly call the methods of the LayoutManager interface; for the most part, layout managers do their work behind the scenes. Once you have created a LayoutManager object and told the container to use it (by calling setLayout()), you're finished with it. The system calls the appropriate methods in the layout manager when necessary.

Therefore, the LayoutManager interface is most important when you are writing a new layout manager; we'll discuss it here because it's the scaffolding on which all layout managers are based. Like any interface, LayoutManager specifies the methods a layout manager must implement but says nothing about how the LayoutManager does its job. Therefore, we'll make a few observations before proceeding. First, a layout manager is free to ignore some of its components; there is no requirement that a layout manager display everything. For example, a Container using a BorderLayout might include thirty or forty components. However, the BorderLayout will display at most five of them (the last component placed in each of its five named areas). Likewise, a CardLayout may manage many components but displays only one at a time.

Second, a layout manager can do anything it wants with the components' minimum and preferred sizes. It is free to ignore either. It makes sense that a layout manager can ignore a preferred size; after all, "preferred" means "give me this if it's available." However, a layout manager can also ignore a minimum size. At times, there is no reasonable alternative: the container may not have enough room to display a component at its minimum size. How to handle this situation is left to the layout manager's discretion. All layout managers currently ignore a component's maximum size, though this may change in the future.

Methods of the LayoutManager Interface

Five methods make up the LayoutManager interface. If you create your own class that implements LayoutManager, you must define all five. As you will see, many of the methods do not have to do anything, but there must still be a stub with the appropriate method signature.

public abstract void addLayoutComponent (String name, Component component)

The addLayoutComponent() method is called only when the program assigns a name to the component when adding it to the layout (i.e., the program calls add(String, Component) rather than simply calling add(Component) or the Java 1.1 add(Component, Object)). It is up to the layout manager to decide what, if anything, to do with the name. For example, BorderLayout uses name to specify an area on the screen in which to display the component. Most layout managers don't require a name and will only implement a stub.

public abstract void removeLayoutComponent (Component component)

The removeLayoutComponent() method's responsibility is to remove component from any internal storage used by the layout manager. This method will probably be stubbed out for your own layouts and do nothing. However, it may need to do something if your layout manager associates components with names.

public abstract Dimension preferredLayoutSize (Container parent)

The preferredLayoutSize() method is called to determine the preferred size of the components within the Container. It returns a Dimension object that contains the required height and width. parent is the object whose components need to be laid out. Usually, the LayoutManager determines how to size parent by calculating the sizes of the components within it and calculating the dimensions required to display them. On other occasions, it may just return parent.setSize().

public abstract Dimension minimumLayoutSize (Container parent)

The minimumLayoutSize() method is called to determine the minimum size of the components within the Container. It returns a Dimension object that contains the required height and width. parent is the object whose components need to be laid out.

public abstract void layoutContainer (Container parent)

The layoutContainer() method is where a LayoutManager does most of its work. The layoutContainer() method is responsible for the positioning of all the Components of parent. Each specific layout positions the enclosed components based upon its own rules.

The LayoutManager2 Interface

Numerous changes were introduced in Java 1.1 to make it conform to various design patterns. These patterns provide consistency in usage and make Java programming easier. The LayoutManager2 interface was introduced for this reason. This new interface solves a problem that occurs when working with the GridBagLayout. While the addLayoutComponent(String, Component) method of LayoutManager works great for BorderLayout and CardLayout, you can't use it for a GridBagLayout. The position of a component in a GridBagLayout is controlled by a number of constraints, which are encapsulated in a GridBagConstraints object. To associate constraints with a component, you needed to call a setConstraints() method. Although this works, it is not consistent with the way you add components to other layouts. Furthermore, as more and more people create their own layout managers, the number of ways to associate positioning information with a component could grow endlessly. LayoutManager2 defines a version of addLayoutComponent() that can be used by all constraint-based layout managers, including older managers like BorderLayout and CardLayout. This method lets you pass an arbitrary object to the layout manager to provide positioning information. Layout managers that need additional information (like the GridBagConstraints object) now implement LayoutManager2 instead of LayoutManager.

In addition to swapping the parameters to the addLayoutComponent(Component, Object), the new LayoutManager2 interface also defines several methods that aren't really needed now but will facilitate the introduction of "peerless components" in a later release. Methods of the LayoutManager2 interface

public abstract void addLayoutComponent(Component comp, Object constraints) (New)

The addLayoutComponent() method is called when a program assigns constraints to the component comp when adding it to the layout. In practice, this means that the program added the component by calling the new method add(Component component, Object constraints) rather than the older methods add(Component component) or add(String name, Component component)). It is up to the layout manager to decide what, if anything, to do with the constraints. For example, GridBagLayout uses constraints to associate a GridBagConstraints object to the component comp. BorderLayout uses constraints to associate a location string (like "Center") with the component.

public abstract Dimension maximumLayoutSize(Container target) (New)

The maximumLayoutSize() method must return the maximum size of the target container under this layout manager. Previously, only minimum and preferred sizes were available. Now a container can have a maximum size. Once layout managers support the concept of maximum sizes, containers will not grow without bounds when additional space is available. If there is no actual maximum, the Dimension should have a width and height of the constant Integer.MAX_VALUE.

public abstract float getLayoutAlignmentX(Container target) (New)

The getLayoutAlignmentX() method must return the alignment of target along the x axis. The return value should be between 0.0 and 1.0. Values nearer 0 mean that the container will be positioned closer to the left edge of the area available. Values nearer 1 mean that the container will be positioned closer to the right. The value 0.5 means the container should be centered.

public abstract float getLayoutAlignmentY(Container target) (New)

The getLayoutAlignmentY() method must return the alignment of target along the y axis. The return value should be between 0.0 and 1.0. Values nearer 0 mean that the container will be positioned closer to the top of the area available. Values nearer 1 mean that the container will be positioned closer to the bottom. The value 0.5 means the container should be centered.

public abstract void invalidateLayout(Container target) (New)

The invalidateLayout() method tells the layout manager that any layout information it has for target is invalid. This method will usually be implemented as a stub (i.e., {}). However, if the layout manager caches any information about target when this method is called, the manager should consider that information invalid and discard it.


Previous Home Next
FileDialog Book Index FlowLayout

Java in a Nutshell Java Language Reference Java AWT Java Fundamental Classes Exploring Java