FileDocCategorySizeDatePackage
JLayeredPane.javaAPI DocJava SE 6 API28314Tue Jun 10 00:26:38 BST 2008javax.swing

JLayeredPane

public class JLayeredPane extends JComponent implements Accessible
JLayeredPane adds depth to a JFC/Swing container, allowing components to overlap each other when needed. An Integer object specifies each component's depth in the container, where higher-numbered components sit "on top" of other components. For task-oriented documentation and examples of using layered panes see How to Use a Layered Pane, a section in The Java Tutorial.

The following text describes this image.

For convenience, JLayeredPane divides the depth-range into several different layers. Putting a component into one of those layers makes it easy to ensure that components overlap properly, without having to worry about specifying numbers for specific depths:

DEFAULT_LAYER
The standard layer, where most components go. This the bottommost layer.
PALETTE_LAYER
The palette layer sits over the default layer. Useful for floating toolbars and palettes, so they can be positioned above other components.
MODAL_LAYER
The layer used for modal dialogs. They will appear on top of any toolbars, palettes, or standard components in the container.
POPUP_LAYER
The popup layer displays above dialogs. That way, the popup windows associated with combo boxes, tooltips, and other help text will appear above the component, palette, or dialog that generated them.
DRAG_LAYER
When dragging a component, reassigning it to the drag layer ensures that it is positioned over every other component in the container. When finished dragging, it can be reassigned to its normal layer.
The JLayeredPane methods moveToFront(Component), moveToBack(Component) and setPosition can be used to reposition a component within its layer. The setLayer method can also be used to change the component's current layer.

Details

JLayeredPane manages its list of children like Container, but allows for the definition of a several layers within itself. Children in the same layer are managed exactly like the normal Container object, with the added feature that when children components overlap, children in higher layers display above the children in lower layers.

Each layer is a distinct integer number. The layer attribute can be set on a Component by passing an Integer object during the add call.
For example:

layeredPane.add(child, JLayeredPane.DEFAULT_LAYER);
or
layeredPane.add(child, new Integer(10));
The layer attribute can also be set on a Component by calling
layeredPaneParent.setLayer(child, 10)
on the JLayeredPane that is the parent of component. The layer should be set before adding the child to the parent.

Higher number layers display above lower number layers. So, using numbers for the layers and letters for individual components, a representative list order would look like this:

5a, 5b, 5c, 2a, 2b, 2c, 1a 
where the leftmost components are closest to the top of the display.

A component can be moved to the top or bottom position within its layer by calling moveToFront or moveToBack.

The position of a component within a layer can also be specified directly. Valid positions range from 0 up to one less than the number of components in that layer. A value of -1 indicates the bottommost position. A value of 0 indicates the topmost position. Unlike layer numbers, higher position values are lower in the display.

Note: This sequence (defined by java.awt.Container) is the reverse of the layer numbering sequence. Usually though, you will use moveToFront, moveToBack, and setLayer.
Here are some examples using the method add(Component, layer, position): Calling add(5x, 5, -1) results in:
5a, 5b, 5c, 5x, 2a, 2b, 2c, 1a 
Calling add(5z, 5, 2) results in:
5a, 5b, 5z, 5c, 5x, 2a, 2b, 2c, 1a 
Calling add(3a, 3, 7) results in:
5a, 5b, 5z, 5c, 5x, 3a, 2a, 2b, 2c, 1a 
Using normal paint/event mechanics results in 1a appearing at the bottom and 5a being above all other components.

Note: that these layers are simply a logical construct and LayoutManagers will affect all child components of this container without regard for layer settings.

Warning: Swing is not thread safe. For more information see Swing's Threading Policy.

Warning: Serialized objects of this class will not be compatible with future Swing releases. The current serialization support is appropriate for short term storage or RMI between applications running the same version of Swing. As of 1.4, support for long term storage of all JavaBeansTM has been added to the java.beans package. Please see {@link java.beans.XMLEncoder}.

version
1.36 02/02/00
author
David Kloba

Fields Summary
public static final Integer
DEFAULT_LAYER
Convenience object defining the Default layer. Equivalent to new Integer(0).
public static final Integer
PALETTE_LAYER
Convenience object defining the Palette layer. Equivalent to new Integer(100).
public static final Integer
MODAL_LAYER
Convenience object defining the Modal layer. Equivalent to new Integer(200).
public static final Integer
POPUP_LAYER
Convenience object defining the Popup layer. Equivalent to new Integer(300).
public static final Integer
DRAG_LAYER
Convenience object defining the Drag layer. Equivalent to new Integer(400).
public static final Integer
FRAME_CONTENT_LAYER
Convenience object defining the Frame Content layer. This layer is normally only use to positon the contentPane and menuBar components of JFrame. Equivalent to new Integer(-30000).
public static final String
LAYER_PROPERTY
Bound property
private Hashtable
componentToLayer
private boolean
optimizedDrawingPossible
Constructors Summary
public JLayeredPane()
Create a new JLayeredPane



//////////////////////////////////////////////////////////////////////////////
//// Container Override methods 
//////////////////////////////////////////////////////////////////////////////
         
      
        setLayout(null);
    
Methods Summary
protected voidaddImpl(java.awt.Component comp, java.lang.Object constraints, int index)

        int layer = DEFAULT_LAYER.intValue();
        int pos;

        if(constraints instanceof Integer) {
            layer = ((Integer)constraints).intValue();
            setLayer(comp, layer);
        } else
            layer = getLayer(comp);

        pos = insertIndexForLayer(layer, index);
        super.addImpl(comp, constraints, pos);
        comp.validate();
        comp.repaint();
        validateOptimizedDrawing();
    
public javax.accessibility.AccessibleContextgetAccessibleContext()
Gets the AccessibleContext associated with this JLayeredPane. For layered panes, the AccessibleContext takes the form of an AccessibleJLayeredPane. A new AccessibleJLayeredPane instance is created if necessary.

return
an AccessibleJLayeredPane that serves as the AccessibleContext of this JLayeredPane

        if (accessibleContext == null) {
            accessibleContext = new AccessibleJLayeredPane();
        }
        return accessibleContext;
    
public intgetComponentCountInLayer(int layer)
Returns the number of children currently in the specified layer.

param
layer an int specifying the layer to check
return
an int specifying the number of components in that layer

        int i, count, curLayer;
        int layerCount = 0;
        
        count = getComponentCount();
        for(i = 0; i < count; i++) {
            curLayer = getLayer(getComponent(i));               
            if(curLayer == layer) {
                layerCount++;
            /// Short circut the counting when we have them all
            } else if(layerCount > 0 || curLayer < layer) {
                break;
            }
        }
        
        return layerCount;
    
protected java.util.HashtablegetComponentToLayer()
Returns the hashtable that maps components to layers.

return
the Hashtable used to map components to their layers

        if(componentToLayer == null)
            componentToLayer = new Hashtable<Component,Integer>(4);
        return componentToLayer;
    
public java.awt.Component[]getComponentsInLayer(int layer)
Returns an array of the components in the specified layer.

param
layer an int specifying the layer to check
return
an array of Components contained in that layer

        int i, count, curLayer;
        int layerCount = 0;
        Component[] results;
        
        results = new Component[getComponentCountInLayer(layer)];
        count = getComponentCount();
        for(i = 0; i < count; i++) {
            curLayer = getLayer(getComponent(i));               
            if(curLayer == layer) {
                results[layerCount++] = getComponent(i);
            /// Short circut the counting when we have them all
            } else if(layerCount > 0 || curLayer < layer) {
                break;
            }
        }
        
        return results;
    
public intgetIndexOf(java.awt.Component c)
Returns the index of the specified Component. This is the absolute index, ignoring layers. Index numbers, like position numbers, have the topmost component at index zero. Larger numbers are closer to the bottom.

param
c the Component to check
return
an int specifying the component's index

        int i, count;
        
        count = getComponentCount();    
        for(i = 0; i < count; i++) {
            if(c == getComponent(i))
                return i;
        }
        return -1;
    
public intgetLayer(java.awt.Component c)
Returns the layer attribute for the specified Component.

param
c the Component to check
return
an int specifying the component's current layer

        Integer i;
        if(c instanceof JComponent)
            i = (Integer)((JComponent)c).getClientProperty(LAYER_PROPERTY);
        else
            i = (Integer)getComponentToLayer().get((Component)c);

        if(i == null)
            return DEFAULT_LAYER.intValue();
        return i.intValue();
    
public static intgetLayer(javax.swing.JComponent c)
Gets the layer property for a JComponent, it does not cause any side effects like setLayer(). (painting, add/remove, etc) Normally you should use the instance method getLayer().

param
c the JComponent to check
return
an int specifying the component's layer

        Integer i;
        if((i = (Integer)c.getClientProperty(LAYER_PROPERTY)) != null)
            return i.intValue();
        return DEFAULT_LAYER.intValue();
    
public static javax.swing.JLayeredPanegetLayeredPaneAbove(java.awt.Component c)
Convenience method that returns the first JLayeredPane which contains the specified component. Note that all JFrames have a JLayeredPane at their root, so any component in a JFrame will have a JLayeredPane parent.

param
c the Component to check
return
the JLayeredPane that contains the component, or null if no JLayeredPane is found in the component hierarchy
see
JFrame
see
JRootPane

        if(c == null) return null;
        
        Component parent = c.getParent();
        while(parent != null && !(parent instanceof JLayeredPane))
            parent = parent.getParent();
        return (JLayeredPane)parent;
    
protected java.lang.IntegergetObjectForLayer(int layer)
Returns the Integer object associated with a specified layer.

param
layer an int specifying the layer
return
an Integer object for that layer

        Integer layerObj;
        switch(layer) {
        case 0:
            layerObj = DEFAULT_LAYER;
            break;
        case 100:
            layerObj = PALETTE_LAYER;
            break;
        case 200:
            layerObj = MODAL_LAYER;
            break;
        case 300:
            layerObj = POPUP_LAYER;
            break;
        case 400:
            layerObj = DRAG_LAYER;
            break;
        default:
            layerObj = new Integer(layer);
        }
        return layerObj;
    
public intgetPosition(java.awt.Component c)
Get the relative position of the component within its layer.

param
c the Component to check
return
an int giving the component's position, where 0 is the topmost position and the highest index value = the count count of components at that layer, minus 1
see
#getComponentCountInLayer

        int i, count, startLayer, curLayer, startLocation, pos = 0;
        
        count = getComponentCount();
        startLocation = getIndexOf(c);

        if(startLocation == -1)
            return -1;
        
        startLayer = getLayer(c);
        for(i = startLocation - 1; i >= 0; i--) {
            curLayer = getLayer(getComponent(i));               
            if(curLayer == startLayer)
                pos++;
            else
                return pos;
        }
        return pos;
    
public inthighestLayer()
Returns the highest layer value from all current children. Returns 0 if there are no children.

return
an int indicating the layer of the topmost component in the pane, or zero if there are no children

        if(getComponentCount() > 0)
            return getLayer(getComponent(0));           
        return 0;
    
protected intinsertIndexForLayer(int layer, int position)
Primitive method that determines the proper location to insert a new child based on layer and position requests.

param
layer an int specifying the layer
param
position an int specifying the position within the layer
return
an int giving the (absolute) insertion-index
see
#getIndexOf

        return insertIndexForLayer(null, layer, position);
    
private intinsertIndexForLayer(java.awt.Component comp, int layer, int position)
This method is an extended version of insertIndexForLayer() to support setLayer which uses Container.setZOrder which does not remove the component from the containment heirarchy though we need to ignore it when calculating the insertion index.

param
comp component to ignore when determining index
param
layer an int specifying the layer
param
position an int specifying the position within the layer
return
an int giving the (absolute) insertion-index
see
#getIndexOf

        int i, count, curLayer;
        int layerStart = -1;
        int layerEnd = -1;
        int componentCount = getComponentCount();
        
        ArrayList<Component> compList =
            new ArrayList<Component>(componentCount);
        for (int index = 0; index < componentCount; index++) {
            if (getComponent(index) != comp) {
                compList.add(getComponent(index));
            }
        }

        count = compList.size();
        for (i = 0; i < count; i++) {
            curLayer = getLayer(compList.get(i));               
            if (layerStart == -1 && curLayer == layer) {
                layerStart = i;
            }   
            if (curLayer < layer) {
                if (i == 0) { 
                    // layer is greater than any current layer  
                    // [ ASSERT(layer > highestLayer()) ] 
                    layerStart = 0;
                    layerEnd = 0;
                } else {
                    layerEnd = i;
                }
                break;
            }
        }

        // layer requested is lower than any current layer
        // [ ASSERT(layer < lowestLayer()) ] 
        // put it on the bottom of the stack
        if (layerStart == -1 && layerEnd == -1)
            return count;

        // In the case of a single layer entry handle the degenerative cases
        if (layerStart != -1 && layerEnd == -1)
            layerEnd = count;
        
        if (layerEnd != -1 && layerStart == -1)
            layerStart = layerEnd;
        
        // If we are adding to the bottom, return the last element
        if (position == -1)
            return layerEnd;
        
        // Otherwise make sure the requested position falls in the 
        // proper range
        if (position > -1 && layerStart + position <= layerEnd)
            return layerStart + position;
        
        // Otherwise return the end of the layer
        return layerEnd;
    
public booleanisOptimizedDrawingEnabled()
Returns false if components in the pane can overlap, which makes optimized drawing impossible. Otherwise, returns true.

return
false if components can overlap, else true
see
JComponent#isOptimizedDrawingEnabled

        return optimizedDrawingPossible;
    
public intlowestLayer()
Returns the lowest layer value from all current children. Returns 0 if there are no children.

return
an int indicating the layer of the bottommost component in the pane, or zero if there are no children

        int count = getComponentCount();
        if(count > 0)
            return getLayer(getComponent(count-1));             
        return 0;
    
public voidmoveToBack(java.awt.Component c)
Moves the component to the bottom of the components in its current layer (position -1).

param
c the Component to move
see
#setPosition(Component, int)

        setPosition(c, -1);
    
public voidmoveToFront(java.awt.Component c)
Moves the component to the top of the components in its current layer (position 0).

param
c the Component to move
see
#setPosition(Component, int)

        setPosition(c, 0);
    
public voidpaint(java.awt.Graphics g)
Paints this JLayeredPane within the specified graphics context.

param
g the Graphics context within which to paint

        if(isOpaque()) {
            Rectangle r = g.getClipBounds();
            Color c = getBackground();
            if(c == null)
                c = Color.lightGray;
            g.setColor(c);
            if (r != null) {
                g.fillRect(r.x, r.y, r.width, r.height);
            }
            else {
                g.fillRect(0, 0, getWidth(), getHeight());
            }
        }
        super.paint(g);
    
protected java.lang.StringparamString()
Returns a string representation of this JLayeredPane. This method is intended to be used only for debugging purposes, and the content and format of the returned string may vary between implementations. The returned string may be empty but may not be null.

return
a string representation of this JLayeredPane.

        String optimizedDrawingPossibleString = (optimizedDrawingPossible ?
						 "true" : "false");

	return super.paramString() +
        ",optimizedDrawingPossible=" + optimizedDrawingPossibleString;
    
public static voidputLayer(javax.swing.JComponent c, int layer)
Sets the layer property on a JComponent. This method does not cause any side effects like setLayer() (painting, add/remove, etc). Normally you should use the instance method setLayer(), in order to get the desired side-effects (like repainting).

param
c the JComponent to move
param
layer an int specifying the layer to move it to
see
#setLayer

        /// MAKE SURE THIS AND setLayer(Component c, int layer, int position)  are SYNCED
        Integer layerObj;

        layerObj = new Integer(layer);
        c.putClientProperty(LAYER_PROPERTY, layerObj);
    
public voidremove(int index)
Remove the indexed component from this pane. This is the absolute index, ignoring layers.

param
index an int specifying the component to remove
see
#getIndexOf

        Component c = getComponent(index);
        super.remove(index);
        if (c != null && !(c instanceof JComponent)) {
            getComponentToLayer().remove(c);
        }
        validateOptimizedDrawing();
    
public voidremoveAll()
Removes all the components from this container.

since
1.5

        Component[] children = getComponents();
        Hashtable cToL = getComponentToLayer();
        for (int counter = children.length - 1; counter >= 0; counter--) {
            Component c = children[counter];
            if (c != null && !(c instanceof JComponent)) {
                cToL.remove(c);
            }
        }
        super.removeAll();
    
public voidsetLayer(java.awt.Component c, int layer)
Sets the layer attribute on the specified component, making it the bottommost component in that layer. Should be called before adding to parent.

param
c the Component to set the layer for
param
layer an int specifying the layer to set, where lower numbers are closer to the bottom

        setLayer(c, layer, -1);
    
public voidsetLayer(java.awt.Component c, int layer, int position)
Sets the layer attribute for the specified component and also sets its position within that layer.

param
c the Component to set the layer for
param
layer an int specifying the layer to set, where lower numbers are closer to the bottom
param
position an int specifying the position within the layer, where 0 is the topmost position and -1 is the bottommost position

        Integer layerObj;
        layerObj = getObjectForLayer(layer);

        if(layer == getLayer(c) && position == getPosition(c)) {
                repaint(c.getBounds());
            return;
        }
        
        /// MAKE SURE THIS AND putLayer(JComponent c, int layer) are SYNCED
        if(c instanceof JComponent)
            ((JComponent)c).putClientProperty(LAYER_PROPERTY, layerObj);
        else
            getComponentToLayer().put((Component)c, layerObj);
        
        if(c.getParent() == null || c.getParent() != this) {
            repaint(c.getBounds());
            return;
        }

        int index = insertIndexForLayer(c, layer, position);

        setComponentZOrder(c, index);
        repaint(c.getBounds());
    
public voidsetPosition(java.awt.Component c, int position)
Moves the component to position within its current layer, where 0 is the topmost position within the layer and -1 is the bottommost position.

Note: Position numbering is defined by java.awt.Container, and is the opposite of layer numbering. Lower position numbers are closer to the top (0 is topmost), and higher position numbers are closer to the bottom.

param
c the Component to move
param
position an int in the range -1..N-1, where N is the number of components in the component's current layer

        setLayer(c, getLayer(c), position);
    
private voidvalidateOptimizedDrawing()

        boolean layeredComponentFound = false;
        synchronized(getTreeLock()) {
            Integer layer = null;

            for (Component c : getComponents()) {
                layer = null;
                if(c instanceof JInternalFrame || (c instanceof JComponent &&
                         (layer = (Integer)((JComponent)c).getClientProperty(
                          LAYER_PROPERTY)) != null)) {
                    if(layer != null && layer.equals(FRAME_CONTENT_LAYER))
                        continue;
                    layeredComponentFound = true;
                    break;
                }
            }
        }
        
        if(layeredComponentFound)
            optimizedDrawingPossible = false;
        else
            optimizedDrawingPossible = true;