JPanel投影

时间:2012-11-13 20:19:49

标签: java swing jpanel shadow

我有一个JPanel元素,我想为它添加一个阴影,我怎样才能为元素添加一个漂亮的褪色阴影?我是否需要使用外部库,或者是否有可以使用的内置库?

示例:

enter image description here

4 个答案:

答案 0 :(得分:25)

所以我研究了扩展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);
    }
}

结果:

Dropshadow

答案 1 :(得分:11)

这是一个完整的 HACK

这将要求您获得JH-Labs Filters的副本用于模糊实现

这是一项昂贵的操作,因为它使用模糊操作,我使用它的原因是会考虑它所遮挡的组件的形状。

enter image description here

你遇到的主要问题是边框不是自己的,透明的,没有办法真正拥有不透明的组件和透明的边框。 Hench the hack

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;

            }
        }
    }
}

使用其他示例更新

阴影边框有局限性,它不能考虑组件的形状,因为绘制边框的时间,组件没有开始,所以我们没有参考点。

enter image description here enter image description here

为了能够生成考虑到组件形状的阴影,我们需要创建一个自定义组件并将边框直接注入到绘制过程中。

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;

    }
}

答案 2 :(得分: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));
        }
    }
}

答案 3 :(得分:3)

你的意思是这样的:

enter image description here

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);
    }
}

<强>参考: