2012-11-13 106 views
17

我有一个JPanel元素,我想为它添加阴影,如何为元素添加一个漂亮的阴影阴影?我需要使用外部库还是有内置的东西可以使用?JPanel阴影

例子:

enter image description here

+0

也有同样的问题在这里:http://stackoverflow.com/questions/3232675/how-can-i-create-a-drop-shadow-inner-glow-and- java-swing的外部发光 –

+0

如果你想要做这种事情,我会考虑使用JavaFX。我相信它有内置的支持做这种事情,希望通过硬件加速。 – millimoose

回答

21

所以我看着swingx延伸JPanel并能实现我一直在寻找与下面的代码结果:

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

+3

意外的低估了你的答案,去了AFK,现在它不会让我满意直到答案被编辑。对不起,伙计,打算upvote。 – Zar

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

参考:

+0

我希望它在边缘淡出。 –

+0

@RyanNaddy我不知道我明白了...请发布一些样本来显示整个预期效果 –

+0

我用一个示例更新了主要问题 –

10

这是一个完整HACK

这需要你有JH-Labs Filters副本模糊实施

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

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()); 
      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 hereenter 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; 

    } 
} 
+0

我想知道这是OP所需要的,我的原始答案是相似的除了具有圆形边框(通过将圆弧尺寸设置为0进行更改)。看起来,如果我的眼睛不欺骗我,边框在角落的底部显示为大(没有弧或角突出),并且围绕图像的其余部分的边缘更薄,也没有从图像角落突出的角或弧。或者是OP的模糊之处? +1虽然很好的代码:) –

+0

原始窗格周围有一个“黑色”线条边框。阴影是通过拍摄组件的快照并使结果模糊以生成简单阴影而开始生成的。目前的阴影固定在东南部,但它并不需要太多的移动;) – MadProgrammer

+0

@DavidKroukamp增加了另外一个例子:P – MadProgrammer

3

简单的投影,你可以工作。你可以看到在这些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)); 
     } 
    } 
} 
+0

这绝对是美丽的。 +1。 – m4heshd