java JPanelドロップシャドウ




swing shadow (4)

シンプルなドロップシャドウは、あなたが取り組むことができます これらのJPanelで実装されていることがわかります。

public class DropShadowPanel extends JPanel {

    private static final long serialVersionUID = 1L;

    public int pixels;

    public DropShadowPanel(int pix) {
        this.pixels = pix;
        Border border = BorderFactory.createEmptyBorder(pixels, pixels, pixels, pixels);
        this.setBorder(BorderFactory.createCompoundBorder(this.getBorder(), border));
        this.setLayout(new BorderLayout());
    }

    @Override
    protected void paintComponent(Graphics g) {
        int shade = 0;
        int topOpacity = 80;
        for (int i = 0; i < pixels; i++) {
            g.setColor(new Color(shade, shade, shade, ((topOpacity / pixels) * i)));
            g.drawRect(i, i, this.getWidth() - ((i * 2) + 1), this.getHeight() - ((i * 2) + 1));
        }
    }
}

私はJPanel要素を持っていて、それにドロップシャドウを追加したいのですが、どのようにしてJPanel要素にドロップシャドウを追加できますか? 外部ライブラリを使用する必要がありますか、または私が使用できるものが組み込まれていますか?

例:


Answer #1

これは完全なHACKです

これには、ぼかし実装のためのJH-Labsフィルタのコピーが必要です

これは、ぼかし操作を使用するため、高価な操作です。私が使用する理由は、シャドウイングしているコンポーネントの形状を考慮に入れるためです。

あなたが持っている主な問題は、ボーダーは自分自身ではなく、透明であることです。本当に不透明なコンポーネントと透明なボーダーを持つ方法はありません。 ハックにハック

public class TestDropShadowBorder {

    public static void main(String[] args) {
        new TestDropShadowBorder();
    }

    public TestDropShadowBorder() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException ex) {
                } catch (InstantiationException ex) {
                } catch (IllegalAccessException ex) {
                } catch (UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Test");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        public TestPane() {
            setBackground(Color.RED);
            setBorder(new EmptyBorder(20, 20, 20, 20));

            setLayout(new BorderLayout());
            JPanel drop = new JPanel();
            drop.setOpaque(false);
            DropShadowBorder border = new DropShadowBorder();
            border.setFillContentArea(true);
            drop.setBorder(new CompoundBorder(border, new LineBorder(Color.BLACK)));

            add(drop);

        }
    }

    public static class DropShadowBorder implements Border {

        protected static final int SHADOW_SIZE = 4;
        protected static final Map<Component, DropShadowBorder.CachedBorder> BORDER_CACHE = new WeakHashMap<Component, CachedBorder>(5);
        private boolean fillContentArea;
        private int shadowSize;
        private float shadowOpacity;
        private Color shadowColor;

        public DropShadowBorder() {

            this(SHADOW_SIZE, Color.BLACK, 0.5f, true);

        }

        public DropShadowBorder(boolean paintContentArea) {

            this(SHADOW_SIZE, Color.BLACK, 0.5f, paintContentArea);

        }

        public DropShadowBorder(int shadowSize) {

            this(shadowSize, Color.BLACK, 0.5f, true);

        }

        public DropShadowBorder(Color shadowColor) {

            this(SHADOW_SIZE, shadowColor, 0.5f, true);

        }

        public DropShadowBorder(int shadowSize, Color showColor) {

            this(shadowSize, showColor, 0.5f, true);

        }

        public DropShadowBorder(int shadowSize, float opacity) {

            this(shadowSize, Color.BLACK, opacity, true);

        }

        public DropShadowBorder(Color shadowColor, float opacity) {

            this(SHADOW_SIZE, shadowColor, opacity, true);

        }

        public DropShadowBorder(int shadowSize, Color shadowColor, float opacity) {

            this(shadowSize, shadowColor, opacity, true);

        }

        public DropShadowBorder(int shadowSize, boolean paintContentArea) {

            this(shadowSize, Color.BLACK, 0.5f, paintContentArea);

        }

        public DropShadowBorder(Color shadowColor, boolean paintContentArea) {

            this(SHADOW_SIZE, shadowColor, 0.5f, paintContentArea);

        }

        public DropShadowBorder(int shadowSize, Color showColor, boolean paintContentArea) {

            this(shadowSize, showColor, 0.5f, paintContentArea);

        }

        public DropShadowBorder(int shadowSize, float opacity, boolean paintContentArea) {

            this(shadowSize, Color.BLACK, opacity, paintContentArea);

        }

        public DropShadowBorder(Color shadowColor, float opacity, boolean paintContentArea) {

            this(SHADOW_SIZE, shadowColor, opacity, paintContentArea);

        }

        public DropShadowBorder(int shadowSize, Color showColor, float opacity, boolean paintContentArea) {

            setShadowSize(shadowSize);
            setShadowColor(showColor);
            setShadowOpacity(opacity);
            setFillContentArea(paintContentArea);

        }

        public void setShadowColor(Color shadowColor) {
            this.shadowColor = shadowColor;
        }

        public void setShadowOpacity(float shadowOpacity) {
            this.shadowOpacity = shadowOpacity;
        }

        public Color getShadowColor() {
            return shadowColor;
        }

        public float getShadowOpacity() {
            return shadowOpacity;
        }

        public void setShadowSize(int size) {

            shadowSize = size;

        }

        public int getShadowSize() {

            return shadowSize;

        }

        public static GraphicsConfiguration getGraphicsConfiguration() {

            return GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();

        }

        public static BufferedImage createCompatibleImage(int width, int height) {

            return createCompatibleImage(width, height, Transparency.TRANSLUCENT);

        }

        public static BufferedImage createCompatibleImage(int width, int height, int transparency) {

            BufferedImage image = getGraphicsConfiguration().createCompatibleImage(width, height, transparency);
            image.coerceData(true);
            return image;

        }

        public static BufferedImage generateShadow(BufferedImage imgSource, int size, Color color, float alpha) {

            int imgWidth = imgSource.getWidth() + (size * 2);
            int imgHeight = imgSource.getHeight() + (size * 2);

            BufferedImage imgMask = createCompatibleImage(imgWidth, imgHeight);
            Graphics2D g2 = imgMask.createGraphics();
            g2.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g2.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
            g2.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
            g2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
            g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
            g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
            g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);

            int x = Math.round((imgWidth - imgSource.getWidth()) / 2f);
            int y = Math.round((imgHeight - imgSource.getHeight()) / 2f);
            g2.drawImage(imgSource, x, y, null);
            g2.dispose();

            // ---- Blur here ---

            BufferedImage imgGlow = generateBlur(imgMask, size, color, alpha);
//
//        BufferedImage imgGlow = ImageUtilities.createCompatibleImage(imgWidth, imgHeight);
//        g2 = imgGlow.createGraphics();
//
//        g2.drawImage(imgMask, 0, 0, null);
//        g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_IN, alpha));
//        g2.setColor(color);
//
//        g2.fillRect(x, y, imgSource.getWidth(), imgSource.getHeight());
//        g2.dispose();
//
//        imgGlow = filter.filter(imgGlow, null);

            // ---- Blur here ----

//        imgGlow = ImageUtilities.applyMask(imgGlow, imgMask, AlphaComposite.DST_OUT);

            return imgGlow;

        }

        public static BufferedImage generateBlur(BufferedImage imgSource, int size, Color color, float alpha) {

            GaussianFilter filter = new GaussianFilter(size);

            int imgWidth = imgSource.getWidth();
            int imgHeight = imgSource.getHeight();

            BufferedImage imgBlur = createCompatibleImage(imgWidth, imgHeight);
            Graphics2D g2d = imgBlur.createGraphics();
            g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
            g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
            g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
            g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
            g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
            g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);

            g2d.drawImage(imgSource, 0, 0, null);
            g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_IN, alpha));
            g2d.setColor(color);

            g2d.fillRect(0, 0, imgSource.getWidth(), imgSource.getHeight());
            g2d.dispose();

            imgBlur = filter.filter(imgBlur, null);

            return imgBlur;

        }

        public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {

            /*
             * Because of the amount of time it can take to render the drop shadow,
             * we cache the results in a static cache, based on the component
             * and the components size.
             * 
             * This allows the shadows to repainted quickly so long as the component
             * hasn't changed in size.
             */

            BufferedImage dropShadow = null;

            DropShadowBorder.CachedBorder cached = BORDER_CACHE.get(c);
            if (cached != null) {

                dropShadow = cached.getImage(c);

            }

            if (dropShadow == null) {

                int shadowSize = getShadowSize();
                float opacity = getShadowOpacity();
                Color color = getShadowColor();

                // Create a blank canvas, from which the actually border can be generated
                // from...
                // The ahadow routine can actually generate a non-rectangular border, but
                // because we don't have a suitable template to run from, we need to 
                // set this up our selves...
                // It would be nice to be able to user the component itself, but this will
                // have to
                BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
                Graphics2D g2d = img.createGraphics();
                g2d.fillRect(0, 0, width - (shadowSize * 2), height - (shadowSize * 2));
                g2d.dispose();

                // Generate the shadow
                BufferedImage shadow = generateShadow(img, shadowSize, getShadowColor(), getShadowOpacity());

                // We need to produce a clipping result, cause the border is painted ontop
                // of the base component...
                BufferedImage clipedShadow = createCompatibleImage(width, height, Transparency.TRANSLUCENT);
                g2d = clipedShadow.createGraphics();
                Shape clip = g2d.getClip();

                // First we create a "area" filling the avaliable space...
                Area area = new Area(new Rectangle(width, height));
                // Then we subtract the space left over for the component
                area.subtract(new Area(new Rectangle(width - (shadowSize * 2), height - (shadowSize * 2))));
                // And then apply the clip
                g2d.setClip(area);
                // Then draw the shadow image
//        g2d.drawImage(shadow, -(shadowSize / 2), -(shadowSize / 2), c);
                g2d.drawImage(shadow, 0, 0, c);
                g2d.setClip(clip);

            if (!c.isOpaque() && isFillContentArea()) {

                area = new Area(new Rectangle(width - (shadowSize * 2), height - (shadowSize * 2)));
                g2d.setColor(c.getBackground());
                g2d.fill(area);

            }

//            g2d.setColor(Color.RED);
//            g2d.drawRect(x, y, width - 1, height - 1);
//
//            g2d.setColor(Color.GREEN);
//            g2d.drawRect(x, y, width - (shadowSize * 2), height - (shadowSize * 2));

                g2d.dispose();

                dropShadow = clipedShadow;
                BORDER_CACHE.put(c, new CachedBorder(dropShadow, c.getSize()));

            }

            g.drawImage(dropShadow, x, y, c);

//        if (!c.isOpaque() && isFillContentArea()) {
//
//            Graphics2D g2d = (Graphics2D) g;
//            
//            Area area = new Area(new Rectangle(width - (shadowSize * 2), height - (shadowSize * 2)));
//            g2d.setColor(c.getBackground());
//            g2d.fill(area);
//
//        }

//        g.setColor(Color.MAGENTA);
//        g.drawRect(x + 1, y + 1, width - (shadowSize * 2) - 1, height - (shadowSize * 2) - 1);

        }

        public Insets getBorderInsets(Component cmpnt) {
            return new Insets(0, 0, getShadowSize() * 2, getShadowSize() * 2);
        }

        public boolean isBorderOpaque() {
            return false;
        }

        /**
         * Returns if the content area should be painted by this border when the
         * parent component is opaque...
         *
         * The problem is, the paintComponent method will paint the WHOLE component
         * background, including the border area. This is a reasonable assumption to
         * make, but it makes the shadow border really show up when the parent
         * component is a different color.
         *
         * This allows the border to take control of that fact.
         *
         * When using it, you will need to try and make this the first border to get
         * painted though :P
         *
         * @return
         */
        public boolean isFillContentArea() {
            return fillContentArea;
        }

        public void setFillContentArea(boolean fill) {

            fillContentArea = fill;

        }

        protected class CachedBorder {

            private BufferedImage image;
            private Dimension size;

            public CachedBorder(BufferedImage border, Dimension size) {

                this.image = border;
                this.size = size;

            }

            public BufferedImage getImage(Component comp) {

                BufferedImage dropShadow = null;

                if (comp.getSize().equals(size)) {

                    dropShadow = image;

                }

                return dropShadow;

            }
        }
    }
}

追加の例で更新

ドロップシャドウの境界には制限があります。コンポーネントの形状を考慮することはできません。境界線が塗りつぶされた時点でコンポーネントが開始されていないため、参照ポイントはありません。

コンポーネントの形状を考慮したドロップシャドウを生成できるようにするには、カスタムコンポーネントを作成し、ボーダーを直接ペイントプロセスに挿入する必要があります。

public class TestDropShadowBorder {

    public static void main(String[] args) {
        new TestDropShadowBorder();
    }

    public TestDropShadowBorder() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException ex) {
                } catch (InstantiationException ex) {
                } catch (IllegalAccessException ex) {
                } catch (UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Test");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        public TestPane() {
            setBackground(Color.RED);
            setBorder(new EmptyBorder(20, 20, 20, 20));
            setLayout(new BorderLayout());
            add(new RoundedPane());
        }
    }

    public class RoundedPane extends JPanel {

        private int shadowSize = 5;

        public RoundedPane() {
            // This is very important, as part of the panel is going to be transparent
            setOpaque(false);
        }

        @Override
        public Insets getInsets() {
            return new Insets(0, 0, 10, 10);
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

        @Override
        protected void paintComponent(Graphics g) {
            int width = getWidth() - 1;
            int height = getHeight() - 1;

            Graphics2D g2d = (Graphics2D) g.create();
            applyQualityProperties(g2d);
            Insets insets = getInsets();
            Rectangle bounds = getBounds();
            bounds.x = insets.left;
            bounds.y = insets.top;
            bounds.width = width - (insets.left + insets.right);
            bounds.height = height - (insets.top + insets.bottom);

            RoundRectangle2D shape = new RoundRectangle2D.Float(bounds.x, bounds.y, bounds.width, bounds.height, 20, 20);

            /**
             * * THIS SHOULD BE CAHCED AND ONLY UPDATED WHEN THE SIZE OF THE
             * COMPONENT CHANGES **
             */
            BufferedImage img = createCompatibleImage(bounds.width, bounds.height);
            Graphics2D tg2d = img.createGraphics();
            applyQualityProperties(g2d);
            tg2d.setColor(Color.BLACK);
            tg2d.translate(-bounds.x, -bounds.y);
            tg2d.fill(shape);
            tg2d.dispose();
            BufferedImage shadow = generateShadow(img, shadowSize, Color.BLACK, 0.5f);

            g2d.drawImage(shadow, shadowSize, shadowSize, this);

            g2d.setColor(getBackground());
            g2d.fill(shape);

            /**
             * THIS ONE OF THE ONLY OCCASIONS THAT I WOULDN'T CALL
             * super.paintComponent *
             */
            getUI().paint(g2d, this);

            g2d.setColor(Color.GRAY);
            g2d.draw(shape);
            g2d.dispose();
        }
    }

    public static GraphicsConfiguration getGraphicsConfiguration() {

        return GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();

    }

    public static BufferedImage createCompatibleImage(int width, int height) {

        return createCompatibleImage(width, height, Transparency.TRANSLUCENT);

    }

    public static void applyQualityProperties(Graphics2D g2) {
        g2.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
        g2.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
        g2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
        g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
        g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
    }

    public static BufferedImage createCompatibleImage(int width, int height, int transparency) {

        BufferedImage image = getGraphicsConfiguration().createCompatibleImage(width, height, transparency);
        image.coerceData(true);
        return image;

    }

    public static BufferedImage generateShadow(BufferedImage imgSource, int size, Color color, float alpha) {

        int imgWidth = imgSource.getWidth() + (size * 2);
        int imgHeight = imgSource.getHeight() + (size * 2);

        BufferedImage imgMask = createCompatibleImage(imgWidth, imgHeight);
        Graphics2D g2 = imgMask.createGraphics();
        applyQualityProperties(g2);

        int x = Math.round((imgWidth - imgSource.getWidth()) / 2f);
        int y = Math.round((imgHeight - imgSource.getHeight()) / 2f);
//            g2.drawImage(imgSource, x, y, null);
        g2.drawImage(imgSource, 0, 0, null);
        g2.dispose();

        // ---- Blur here ---

        BufferedImage imgShadow = generateBlur(imgMask, size, color, alpha);

        return imgShadow;

    }

    public static BufferedImage generateBlur(BufferedImage imgSource, int size, Color color, float alpha) {

        GaussianFilter filter = new GaussianFilter(size);

        int imgWidth = imgSource.getWidth();
        int imgHeight = imgSource.getHeight();

        BufferedImage imgBlur = createCompatibleImage(imgWidth, imgHeight);
        Graphics2D g2d = imgBlur.createGraphics();
        applyQualityProperties(g2d);

        g2d.drawImage(imgSource, 0, 0, null);
        g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_IN, alpha));
        g2d.setColor(color);

        g2d.fillRect(0, 0, imgSource.getWidth(), imgSource.getHeight());
        g2d.dispose();

        imgBlur = filter.filter(imgBlur, null);

        return imgBlur;

    }
}

Answer #2

だから私はJPanelを拡張し、私が探していた結果を次のコードで達成することができたswingxを調べました:

public class Canvas extends JXPanel{

    public Canvas(){
        DropShadowBorder shadow = new DropShadowBorder();
        shadow.setShadowColor(Color.BLACK);
        shadow.setShowLeftShadow(true);
        shadow.setShowRightShadow(true);
        shadow.setShowBottomShadow(true);
        shadow.setShowTopShadow(true);
        this.setBorder(shadow);
    }
}

そして結果:


Answer #3

このような意味ですか?

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.RenderingHints;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class ShadowTest {

    private JFrame frame;

    public ShadowTest() {
        initComponents();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new ShadowTest();
            }
        });
    }

    private void initComponents() {
        frame = new JFrame();
        frame.setTitle("Example");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//app exited when frame closes
        frame.setResizable(false);
        frame.setLayout(new GridBagLayout());
        GridBagConstraints gc = new GridBagConstraints();
        gc.fill = GridBagConstraints.HORIZONTAL;
        gc.insets = new Insets(10, 10, 10, 10);
        frame.add(new RoundedPanel(), gc);

        //pack frame (size components to preferred size)
        frame.pack();
        frame.setVisible(true);//make frame visible
    }
}

class RoundedPanel extends JPanel {

    /**
     * Stroke size. it is recommended to set it to 1 for better view
     */
    protected int strokeSize = 1;
    /**
     * Color of shadow
     */
    protected Color shadowColor = Color.black;
    /**
     * Sets if it drops shadow
     */
    protected boolean shady = true;
    /**
     * Sets if it has an High Quality view
     */
    protected boolean highQuality = true;
    /**
     * Double values for Horizontal and Vertical radius of corner arcs
     */
    protected Dimension arcs = new Dimension(0, 0);
    //protected Dimension arcs = new Dimension(20, 20);//creates curved borders and panel
    /**
     * Distance between shadow border and opaque panel border
     */
    protected int shadowGap = 10;
    /**
     * The offset of shadow.
     */
    protected int shadowOffset = 4;
    /**
     * The transparency value of shadow. ( 0 - 255)
     */
    protected int shadowAlpha = 150;
    int width = 300, height = 300;

    public RoundedPanel() {
        super();
        setOpaque(false);
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Color shadowColorA = new Color(shadowColor.getRed(),
                shadowColor.getGreen(), shadowColor.getBlue(), shadowAlpha);
        Graphics2D graphics = (Graphics2D) g;

        //Sets antialiasing if HQ.
        if (highQuality) {
            graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                    RenderingHints.VALUE_ANTIALIAS_ON);
        }

        //Draws shadow borders if any.
        if (shady) {
            graphics.setColor(shadowColorA);
            graphics.fillRoundRect(
                    shadowOffset,// X position
                    shadowOffset,// Y position
                    width - strokeSize - shadowOffset, // width
                    height - strokeSize - shadowOffset, // height
                    arcs.width, arcs.height);// arc Dimension
        } else {
            shadowGap = 1;
        }

        //Draws the rounded opaque panel with borders.
        graphics.setColor(getBackground());
        graphics.fillRoundRect(0, 0, width - shadowGap,
                height - shadowGap, arcs.width, arcs.height);
        graphics.setColor(getForeground());
        graphics.setStroke(new BasicStroke(strokeSize));
        graphics.drawRoundRect(0, 0, width - shadowGap,
                height - shadowGap, arcs.width, arcs.height);

        //Sets strokes to default, is better.
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(width, height);
    }
}

参照:







shadow