What follows is the highlighted source code with comments. You can also download this file directly: LayeredPanel.java.
/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package layers; import java.awt.AlphaComposite; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.awt.image.BufferedImage; import java.util.LinkedList; import java.util.ListIterator; import javax.swing.JPanel; /** * * @author pat */ public class LayeredPanel extends JPanel implements MouseListener, MouseMotionListener { LinkedList<Layer> layers = new LinkedList<Layer>(); Layer active = null; BufferedImage layer_output; public LayeredPanel() { this.addMouseListener(this); this.addMouseMotionListener(this); } public void setNoActiveLayer() { active=null; repaint(); } public void setActiveLayer(Layer l) { active = l; repaint(); } /** * Add a layer which draws after all other layers. */ public void addTopLayer(Layer l) { layers.addLast(l); this.repaintAllLayers(); } /** * Add a layer which draws before all previous layers. */ public void addBottomLayer(Layer l) { layers.addFirst(l); this.repaintAllLayers(); } public void removeLayer(Layer l) { layers.remove(l); this.repaintAllLayers(); } public void moveActiveToBottom() { moveLayerToBottom(active); } public void moveLayerToBottom(Layer l) { layers.remove(l); addBottomLayer(l); this.repaintAllLayers(); } public void moveActiveToTop() { moveLayerToTop(active); } public void moveLayerToTop(Layer l) { layers.remove(l); addTopLayer(l); this.repaintAllLayers(); } public void moveActiveLayerUp() { moveLayerUp(active); } public void moveLayerUp(Layer l) { ListIterator<Layer> it = layers.listIterator(); Layer last = null; while ((it.hasNext()) && (last != l)) { last = it.next(); } if ((last == l) && (it.hasNext())) { it.remove(); it.next(); it.add(l); this.repaintAllLayers(); } } public void moveActiveLayerDown() { moveLayerDown(active); } public void moveLayerDown(Layer l) { ListIterator<Layer> it = layers.listIterator(layers.size()); Layer last = null; while ((it.hasPrevious()) && (last != l)) { last = it.previous(); } if ((last == l) && (it.hasPrevious())) { it.remove(); it.previous(); it.add(l); this.repaintAllLayers(); } } public void repaintAllLayers() { layer_output = null; repaint(); } @Override protected void paintComponent(Graphics grphcs) { super.paintComponent(grphcs); if ((layer_output == null) || (layer_output.getWidth() != getWidth()) || (layer_output.getHeight() != getHeight())) { layer_output = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB); Graphics2D imgG = layer_output.createGraphics(); imgG.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // Anti-aliasing looks pretty! imgG.setComposite(AlphaComposite.Clear); imgG.fillRect(0, 0, getWidth(), getHeight()); imgG.setComposite(AlphaComposite.SrcOver); for (Layer l : layers) { l.render(imgG); } imgG.dispose(); } Graphics2D g = (Graphics2D) grphcs; // Better to draw with a Graphics2D object. g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // Anti-aliasing looks pretty! g.drawImage(layer_output, 0, 0, this); if (active != null) { active.renderActive(g); } } // Mouse handling: public void mouseClicked(MouseEvent me) { if (active != null) { active.mouseClicked(me); } } public void mouseEntered(MouseEvent me) { if (active != null) { active.mouseEntered(me); } } public void mouseExited(MouseEvent me) { if (active != null) { active.mouseExited(me); } } public void mousePressed(MouseEvent me) { if (active != null) { active.mousePressed(me); } } public void mouseReleased(MouseEvent me) { if (active != null) { active.mouseReleased(me); } } public void mouseDragged(MouseEvent me) { if (active != null) { active.mouseDragged(me); } } public void mouseMoved(MouseEvent me) { if (active != null) { active.mouseMoved(me); } } }