Have you ever needed to write a simple graphical user interface (GUI) but didn't have the right kind of layout manager? Do you hate to use a layout manager that takes you longer to understand than to make your GUI? If this is the case, you're probably not a big fan of the GridBagLayout manager and its complexities.
This article describes AttachmentLayout, a layout manager that allows for GUI components (buttons, labels, lists, etc.) to be placed inside a container to its edges using spatial relationships. It's a simple but effective layout manager that can be easily visualized and implemented with only one line per component.
Background and Concept
The AttachmentLayout manager was developed for two reasons. The first is to allow construction of a GUI with only a few basic components placed inside a frame or dialog box - this can't be easily done using FlowLayout, BorderLayout, GridLayout, or BoxLayout. These first three layout managers are supplied by all implementations of the Java Development Kit (JDK) and are the easiest to use and understand. The last layout manager, BoxLayout, is included in the latest implementations of the Swing package and is more difficult to use. In many simple GUIs, GridLayout and FlowLayout can't produce the desired component layouts. BorderLayout and BoxLayout can produce many simple GUIs, but with additional overhead and less efficiency. Almost all GUIs can be constructed with the exact pixel placement of the components or using the GridBagLayout. Exact pixel placement would get the job done, but most experienced GUI developers wouldn't recommend this course of action as it can lead to less portable code.
The second reason for the development of the AttachmentLayout manager is that the GridBagLayout is complex and can be cumbersome when constructing a simple GUI. The AttachmentLayout enables you to get to the heart of the software engineering that the simple GUI supports.
AttachmentLayout was designed to emulate certain aspects of the layout managers available in X-Windows/Motif without the complexities of a GridBagLayout manager or the inefficiencies of the others. The concept behind the AttachmentLayout manager is the ability to have a GUI element such as a button be connected (hence the word attached) to a container edge and, in some cases, to other GUI elements. In Figure 1 a button has the container as an attachment on its right side with a specified pixel offset between the button and the container. If the user stretches the right side of the container during program execution, the button keeps the same dimensions but follows the right side of the container as it's stretched. In another example, if the container is attached to the button's top, bottom, left, and right sides, the button will increase its width and height as the container's width and height are increased.
Figure 1: A button has its right side attached to the container
The AttachmentLayout manager consists of two classes. The first, Attachment.java (see Listing 1), defines how a single component is attached to the container and to other components. It allows a component to have an attachment to its top, bottom, left, or right side. (Listings 1-4 can be found below.) An additional feature of Attachment.java is pixel padding. Padding is the number of pixels a component will always have between it and the component it has an attachment to on one of its sides. Attachment.java has three constructors defined, and the one most commonly used is shown below.
public Attachment( leftPad, leftComp, rightPad, rightComp, bottomPad, bottomComp, topPad, topComp)
The first input parameter (leftPad) is the left pixel padding between a component and its left-side attached component. LeftComp is the component that will be attached to the left side. The same follows for the right, bottom, and top attachments, respectively. If you don't wish to have an attachment to one or more sides, the component input parameter for that particular side should be set to null. An instance of Attachment is assigned to each component when it's added to a container specifying an AttachmentLayout. Also stored in each instance of Attachment are the pixel location, width, and height of the component. All these fields are necessary to compute the location and size of each component when the container is resized. The size and location of each component is computed in AttachmentLayout.java.
The second class is AttachmentLayout.java (see Listing 2). To use the AttachmentLayout, a container must specify its use with setLayout( new AttachmentLayout() ). AttachmentLayout has one constructor with no parameters. The constructor's only function is to initialize a Java Vector that will hold all the components to be placed inside the container. This class implements the LayoutManager2 interface in the java.awt package and must implement several methods to function properly as a layout manager. In the case of our layout manager, the most important methods of the interface that need to be defined are addLayoutComponent and layoutContainer.
The Java Virtual Machine (JVM) calls addLayoutComponent when a program calls the add method (Component comp, Object constraints) to add a component to a container. For the AttachmentLayout manager, an object may be added to a container by calling the add method with the component to be added and an instance of the Attachment class as the constraint object.
As can be seen in Listing 2, the addLayoutComponent method takes the input component and adds it to the list of components in the container. This list is used in the layoutContainer method, which is the real guts of the AttachmentLayout class. It's called by the JVM to do the actual rendering of the container. This method computes the dimensions and the location of every component of the container. The first function the layoutContainer method performs is to loop through every component in the container. If the component has an attachment to the container, it computes the upper-right and lower-left locations of the component based on the information stored in the component's associated instance of Attachment. From these two positions, the width and height can be calculated and the component can be placed inside the container with the proper spatial relationship to the container.
The second function of layoutContainer is to determine the component's relationship to other noncontainer components that it has attachments with inside the container. Again, looping through all components does this, and if it has a noncontainer attachment, it computes its upper-right and lower-left positions based on the components associated instance of Attachment. The remaining methods of AttachmentLayout are required by the LayoutManager2 interface, but as these are seldom used they're left to the reader.
Figure 2 shows a simple GUI made using javax.swing components. The white area is a JPanel named mainPanel and consists of a JLabel. Along the bottom of the GUI are two JButtons named Button 1 and Button 2. The main emphasis of a GUI of this kind is usually the contents of the large mainPanel, so it's afforded the largest area of the GUI. The content pane of the JFrame uses an AttachmentLayout manager to position mainPanel. The desire is to have mainPanel expand in every direction as the JFrame is resized. The following lines of code demonstrate how this is done.
Container p = JFrame.getContentPane();
Figure 2: Sample GUI
The first line of code gets the content pane of the JFrame. All components added to a JFrame are actually added to its content pane. Line 2 instructs the content pane to use an AttachmentLayout for its layout manager. Line 3 adds mainPanel to the content pane. Notice that the second argument to the add() method is an instance of the Attachment class. This form of add() is necessary since AttachmentLayout implements the java.awt.LayoutManager2 interface. The instance of Attachment has eight parameters. The first two parameters (5,p) tell AttachmentLayout how to construct the left attachment of mainPanel. The integer 5 is the number of pixels that will always be between mainPanel and the component it will be attached to on its left side (e.g., the content pane of the JFrame). The next two parameters are also 5 and pane. They tell the AttachmentLayout how to construct the right-side attachment of mainPanel. Parameters 5 and 6 describe the bottom attachment. In this case we want mainPanel to be spaced 10 pixels above Button 1. The mainPanel could also have a bottom attachment to Button 2 to provide the same results. And finally, the last two parameters construct the top attachment of mainPanel, always 5 pixels from the top of the content pane.
Along the bottom part of the GUI are Button 1 and Button 2. This GUI's intent is to have both buttons stay the same size and in relatively the same location during the resizing of the JFrame. Both buttons are also added to the content pane using the AttachmentLayout manager. The following lines of code demonstrate this:
pane.add( button1, new Attachment(5,p,0,null,5,p,0,null));
The first line of code adds Button 1 to the content pane. It will be spaced 5 pixels away from the content pane on the left and bottom. The right and top attachments are set to null since we don't want the width or height to change as the frame is resized. Button 2 is added in a similar fashion but with attachments on the right and bottom. If you don't want to change a component's width or height, the size of the component must be set using the setSize() method of the component before it's added to the container. If this method isn't called before it's added, the preferred size of the component is used. Otherwise the component would still be placed inside the container, but at a default width and height of zero (see Listing 3 for the complete example).
pane.add( button2, new Attachment(0,null,5,p,5,p,0,null));
Figure 3 shows the same GUI as in Figure 2 but the screenshot was taken after the JFrame increased in width and height. Notice the sizes and placement of the components in Figure 3 as compared to Figure 2.
Figure 3: GUI after JFrame is increased
As mentioned previously, this same GUI could be constructed using GridBagLayout. Listing 4 shows the steps necessary to construct the same GUI via GridBagLayout. It requires the use of a helper class, similar to Attachment.java, called GridBagConstraints. GridBagConstraints keeps track of all the characteristics describing the placement of a component inside a container. In our example, mainPanel required the use of eight different parameters and one class just to describe its placement.
For each button it also takes eight parameters and one class. The BuildConstraints() method simplifies the construction of the settings of the cell location, size, and proportions of the container it will fill. Using this method reduced the amount of code necessary to construct the GUI. Other GridBagConstraints parameters to consider are the anchor and the fill. They tell the layout manager how they're positioned within the container and how they fill cells. Note that in GridBagLayout, components are placed in a grid of cells. The cells don't have to be the same size, which makes it even more difficult to mentally visualize the container layout. Finally, both buttons required an instance of the Inset class to be set inside the GridBagConstraints object in order to have the proper padding around the buttons.
The use of our simple GUI example provides a clear picture of the relative ease in using the
AttachmentLayout manager versus the GridBagLayout manager. The AttachmentLayout manager essentially required only four lines of code to arrange the main panel and both buttons in the JFrame's content pane. In comparison, using the GridBagLayout required 18 lines of code and a helper method (seven additional lines and two instances of the Inset class).
Using AttachmentLayout, this example GUI can be easily visualized and the code written in less than five minutes. Constructing the same GUI, but using GridBagLayout, took at least twice as long and the use of a manual to remember all the options.
AttachmentLayout was also easier to use than the BorderLayout and the BoxLayout manager. The BorderLayout required seven lines of code and the BoxLayout required eight to produce the exact same GUI, but both of these required the use of additional panels and layout managers.
As with all layout managers, the AttachmentLayout manager has its limitations. It's good for simple GUIs that may not be easily handled by other layout managers. More complex GUIs will require a layout manager such as the GridBagLayout. Also, it should be used only when components inside a container don't depend on the resizing of other noncontainer components that it is has an attachment to. This limitation is what some experienced Motif/X-Windows developers know as circular dependency. As an example, if Button A has a right-side attachment to Button B and Button B has a left-side attachment to Button A, there's a circular dependency. Circular dependencies will produce unexpected results and in some implementations of Motif/X-Windows they will produce an infinite loop. In our case the size and placement of both components depends on the changes of the other, but only one will take effect, depending on the order in which the components were added to the container.
In my five years of Java programming I've been required to construct relatively simple user input or informational display GUIs on many occasions. But I never have quite the perfect, easy-to-use layout manager that would help me construct my GUI in the shortest amount of time.
The basic layout managers that come with Sun Microsystems' JDK cover both ends of the spectrum when it comes to use and functionality - easy and simple to hard and complex. The simpler ones are GridLayout, FlowLayout, and BorderLayout. The harder and more complex one is the GridBagLayout. BorderLayout or BoxLayout can produce our simple example GUI or more complex GUIs, but will require the use of additional nested panels and layout managers. AttachmentLayout.java with its concept of attachments is a simple layout manager, but with a different kind of capability, and as such it's another useful tool that can be put in the GUI developer's arsenal.
Valor Dodd is a Java-certified senior software engineer at Lockheed Martin in Denver, Colorado. He has more than 20 years of software experience developing computer graphics and GUI applications for the telephone and defense industries. He can be contacted at [email protected]
Download Assoicated Source Files (Zip format ~ 3.46 KB)