The JFC Swing Tutorial: A Guide to Constructing GUIs (2nd Edition)
< Day Day Up > |
A layered pane is a Swing container that provides a third dimension for positioning components : depth , also known as Z order . When adding a component to a layered pane, you specify its depth as an integer. The higher the number, the higher the depth. If components overlap, components at a higher depth are drawn on top of components at a lower depth. The relationship between components at the same depth is determined by their positions within the depth.
Version Note: In 1.5, we expect that API will be added to allow direct manipulation of a component's Z order within a container. When this is available, you won't need to use a JLayeredPane to assign a Z order to a lightweight component.
Every Swing container that has a root panesuch as JFrame , JApplet , JDialog , or JInternalFrame automatically has a layered pane. Most programs don't explicitly use the root pane's layered pane, so we don't discuss it in this section. You can find information about it in How to Use Root Panes (page 316), which provides an overview, and in The Layered Pane (page 320), which has further details. This section concentrates on telling you how to create your own layered pane and use it anywhere you might use a regular Swing container. Swing provides two layered pane classes. The first, JLayeredPane , [79] is the class that root panes use and is the class used by the example in this section. The second, JDesktopPane , is a JLayeredPane subclass that's specialized for the task of holding internal frames . For examples of using JDesktopPane , see How to Use Internal Frames (page 245). [79] JLayeredPane API documentation: http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/JLayeredPane.html. The LayeredPaneDemo application creates a layered pane and places overlapping, colored labels at different depths, as shown in Figure 27. Figure 27. The LayeredPaneDemo application.
Try This:
Here's the code from LayeredPaneDemo.java that creates the layered pane: layeredPane = new JLayeredPane(); layeredPane.setPreferredSize(new Dimension(300, 310)); layeredPane.setBorder(BorderFactory.createTitledBorder( "Move the Mouse to Move Duke")); layeredPane.addMouseMotionListener(new MouseMotionAdapter() { ... }); The code uses JLayeredPane 's only constructorthe no-argument constructorto create the layered pane. The rest of the code uses methods inherited from superclasses to give the layered pane a preferred size and a border, and to add a mouse-motion listener to it. The mouse-motion listener just moves the Duke image around in response to mouse movement. Although we don't show the code here, the example adds the layered pane to the frame's content pane. As we'll show you a bit later, you add components to a layered pane using an add method. When adding a component to a layered pane, you specify the component's depth and, optionally , its position within its depth. The layered pane in the demo program contains six labelsthe five colored labels and a sixth one that displays the Duke image. As the program demonstrates , both the depth of a component and its position within that depth can change dynamically. Adding Components and Setting Component Depth
Here's the code from the sample program that adds the colored labels to the layered pane: for (int i = 0; i < ...number of labels...; i++) { JLabel label = createColoredLabel(...); layeredPane.add(label, new Integer(i)) ... } You can find the implementation of the createColoredLabel method in the source code for the program. It just creates an opaque JLabel initialized with a background color , a border, some text, and a size. The example program uses a two-argument version of the add method. The first argument is the component to add, the second is an Integer object, specifying the depth. This program uses the for loop's iteration variable to specify depths. The actual values don't matter much. What matters is the relative value of the depths and that you are consistent within your program in how you use each depth.
Note: If you use the root pane's layered pane, be sure to use its depth conventions. Refer to The Layered Pane (page 320) for details. That section shows you how to modify LayeredPaneDemo to use the root pane's layered pane. With the modifications, you can see how the dragging Duke image relates to the combo box in the control panel.
As you can see from the example program, if components overlap, components at a higher depth are on top of components at a lower depth. To change a component's depth dynamically, use the setLayer method. In the example, the user can change Duke's layer by making a selection from the combo box. Here's the actionPerformed method of the action listener registered on the combo box: public void actionPerformed(ActionEvent e) { int position = onTop.isSelected() ? 0 : 1; layeredPane.setLayer(dukeLabel, layerList.getSelectedIndex(), position); } The setLayer method used here takes three arguments: the component whose depth is to be set, the new depth, and the position within the depth. JLayeredPane has a two-argument version of setLayer that takes only the component and the new depth. That method puts the component at the bottom position in its depth.
Note: When adding a component to a layered pane you specify the layer with an Integer . When using setLayer to change a component's layer, you use an int . You might think that if you use an int instead of an Integer with the add method, the compiler would complain or your program would throw an illegal argument exception. But the compiler says nothing, which results in a common layered pane problem. You can use the API tables at the end of this section to check the types of the arguments and return values for methods that deal with layers .
Setting a Component's Position within Its Depth
The following code creates the label that displays Duke's image and then adds the label to the layered pane. final ImageIcon icon = createImageIcon("images/dukeWaveRed.gif"); ... dukeLabel = new JLabel(icon); ... dukeLabel.setBounds(15, 225, icon.getIconWidth(), icon.getIconHeight()); ... layeredPane.add(dukeLabel, new Integer(2), 0); This code uses the three-argument version of the add method. The third argument specifies the Duke label's position within its depth, which determines the component's relationship with other components at the same depth. Positions are specified with an int between -1 and ( n - 1), where n is the number of components at the depth. Unlike layer numbers , the smaller the position number, the higher the component within its depth. (See Figure 28.) Using -1 is the same as using n - 1; it indicates the bottom-most position. Using 0 specifies that the component should be in the topmost position within its depth. Figure 28. With the exception of -1, a lower position number indicates a higher position within a depth.
A component's position within its layer can change dynamically. In the example, you can use the check box to determine whether the Duke label is in the top position at its depth. Here's the actionPerformed method for the action listener registered on the check box: public void actionPerformed(ActionEvent e) { if (onTop.isSelected()) layeredPane.moveToFront(dukeLabel); else layeredPane.moveToBack(dukeLabel); } When the user selects the check box, the moveToFront method moves Duke to the front (position 0). And when the user deselects the check box, Duke gets moved to the back with the moveToBack method. You can also use the setPosition method or the three-argument version of setLayer to change a component's position. Laying Out Components in a Layered Pane
By default a layered pane has no layout manager. This means that you typically have to write the code that positions and sizes the components you put in it. The example uses the setBounds method to set the size and position of each of the labels: dukeLabel.setBounds(15, 225, icon.getIconWidth(), icon.getIconHeight()); ... label.setBounds(origin.x, origin.y, 140, 140); When the user moves the mouse around, the program calls setPosition to change Duke's position: dukeLabel.setLocation(e.getX()-XFUDGE, e.getY()-YFUDGE); Although a layered pane has no layout manager by default, you can still assign a layout manager to it. All of the layout managers provided by the Java platform arrange the components as if they were all on one layer.
Figure 29. A screenshot of LayeredPaneDemo2 , a version of the previous demo that sets the layered pane's layout manager to an instance of GridLayout , using that layout manager to lay out six colored labels.
Many programs use intermediate containers (such as panels) and their layout managers to lay out components on the same layer, but use absolute positioning to lay out components on different layers. For more information about absolute positioning, see Doing without a Layout Manager (Absolute Positioning) (page 100). The Layered Pane API
Tables 41 through 43 list the commonly used JLayeredPane constructors and methods. Other methods you are most likely to invoke on a JLayeredPane object are those it inherits from its superclasses, such as setBorder , setPreferredSize , and so on. See The JComponent API (page 55) for tables of commonly used inherited methods. You should also refer to the JLayeredPane API documentation: http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/JLayeredPane.html. Table 41. Creating or Getting a Layered Pane
Table 42. Layering Components
Table 43. Setting Components' Intra-Layer Positions
Examples That Use Layered Panes
This table shows examples that use JLayeredPane and where those examples are described.
|
< Day Day Up > |