import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.EventQueue; import java.awt.Graphics; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.lang.reflect.Field; import java.util.LinkedList; import javax.swing.BoxLayout; import javax.swing.ButtonGroup; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.border.LineBorder; public class PaintOrderDemo extends JFrame implements ActionListener { private int onTopIndex = 2; public static void main(String[] args) throws Exception { EventQueue.invokeLater(new Runnable() { public void run() { new PaintOrderDemo(); } }); } public PaintOrderDemo() { JPanel p = new ColorBoxContainer(); p.setLayout(new BoxLayout(p, BoxLayout.LINE_AXIS)); add(p); p.add(new ColorBox(Color.RED)); p.add(new ColorBox(Color.GREEN)); p.add(new ColorBox(Color.BLUE)); JPanel optionsPanel = new JPanel(); JRadioButton rb1 = new JRadioButton("red", false); rb1.setActionCommand("0"); rb1.addActionListener(this); JRadioButton rb2 = new JRadioButton("green", false); rb2.setActionCommand("1"); rb2.addActionListener(this); JRadioButton rb3 = new JRadioButton("blue", true); rb3.setActionCommand("2"); rb3.addActionListener(this); ButtonGroup group = new ButtonGroup(); group.add(rb1); group.add(rb2); group.add(rb3); optionsPanel.add(rb1); optionsPanel.add(rb2); optionsPanel.add(rb3); add(optionsPanel, BorderLayout.SOUTH); setTitle(getClass().getSimpleName()); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); pack(); setLocationRelativeTo(null); setVisible(true); } class ColorBox extends JPanel { private Color color; public ColorBox(Color color) { this.color = color; setOpaque(false); setPreferredSize(new Dimension(160, 160)); setBorder(new LineBorder(color, 4)); } @Override protected void paintComponent(Graphics g) { g.setColor(new Color(0x80FFFFFF & color.getRGB(), true)); g.fillRect(0, 0, getWidth(), getHeight()); } @Override public void setBounds(int x, int y, int width, int height) { int index = 0; for (Component c : getParent().getComponents()) { if (c == this) break; index++; } //overlap 25 pixels x += index * -25; super.setBounds(x, y, width, height); } } class ColorBoxContainer extends JPanel { @Override public boolean isOptimizedDrawingEnabled() { return false; } private LinkedList arrangeChildComponents() { LinkedList components = new LinkedList(); for (int k = 0; k < getComponentCount(); k++) { if (k == onTopIndex) components.addFirst(getComponent(k)); else components.add(getComponent(k)); } return components; } @Override protected void paintChildren(Graphics g) { final int ANCESTOR_USING_BUFFER = 1; final int IS_PAINTING_TILE = 2; synchronized (getTreeLock()) { int i = getComponentCount() - 1; if (i < 0) return; Rectangle clipBounds = g.getClipBounds(); if (clipBounds == null) clipBounds = new Rectangle(0, 0, getWidth(), getHeight()); //create list - the first item in the list will be painted on top LinkedList components = arrangeChildComponents(); for (; i >= 0; i--) { Component comp = components.get(i); if (!(comp instanceof JComponent) || !comp.isVisible()) continue; JComponent c = (JComponent) comp; Rectangle cr = c.getBounds(new Rectangle()); if (!clipBounds.intersects(cr)) continue; Graphics cg = g.create(cr.x, cr.y, cr.width, cr.height); cg.setColor(c.getForeground()); cg.setFont(c.getFont()); boolean resetFlag = false; if (getFlag(ANCESTOR_USING_BUFFER)) { setFlag(c, ANCESTOR_USING_BUFFER, true); resetFlag = true; } if (getFlag(IS_PAINTING_TILE)) { setFlag(c, IS_PAINTING_TILE, true); resetFlag = true; } c.paint(cg); cg.dispose(); if (resetFlag) { setFlag(c, ANCESTOR_USING_BUFFER, false); setFlag(c, IS_PAINTING_TILE, false); } } } } private boolean getFlag(int aFlag) { int flags = 0; try { Field field = JComponent.class.getDeclaredField("flags"); field.setAccessible(true); flags = (Integer) field.get(this); } catch (Exception e) { throw new RuntimeException(e); } int mask = (1 << aFlag); return ((flags & mask) == mask); } private void setFlag(JComponent c, int aFlag, boolean aValue) { int flags = 0; try { Field field = JComponent.class.getDeclaredField("flags"); field.setAccessible(true); flags = (Integer) field.get(c); } catch (Exception e) { throw new RuntimeException(e); } if (aValue) flags |= (1 << aFlag); else flags &= ~(1 << aFlag); try { Field field = JComponent.class.getDeclaredField("flags"); field.setAccessible(true); field.set(c, flags); } catch (Exception e) { throw new RuntimeException(e); } } } public void actionPerformed(ActionEvent evt) { onTopIndex = Integer.parseInt(evt.getActionCommand()); repaint(); } }