2011-08-31 48 views
2

我在我的swing應用程序中使用了Nimbus外觀和感覺,它非常酷。
我注意到它是一個「純粹」的外觀和感覺:它「皮膚」組件,但不添加新的圖形元素。
我不知道它的渲染技術的某些部分是可重複使用的,例如類:
swing nimbus ShadowEffect

javax.swing.plaf.nimbus.ShadowEffect 

可添加陰影像JLabel的其他元素,即在默認情況下沒有影子?

+2

發生了什麼事,當你試圖;-) – kleopatra

+1

'java.lang.IllegalAccessError:試圖訪問類com.sun.java.swing.plaf.nimbus.DropShadowEffect' – oliholz

+0

好完成,oliholz :-)。向前一小步。 – AgostinoX

回答

2

我得到了IllegalAccess,所以我複製了這個類,如果我需要這個在一個小應用程序。
我知道這並不好,但ShadowEffect不能用於其他任何類。 :(

例子:

public class Example extends JFrame { 
    private JSlider slider = new JSlider(JSlider.VERTICAL,0,20,2); 
    private JTextField txt = new JTextField(); 
    private BufferedImage raw = null; 
    private Image src = null; 
    private Rectangle rect = new Rectangle(400,200); 

    public Example() { 
     slider.addChangeListener(new ChangeListener() { 
      @Override 
      public void stateChanged(ChangeEvent e) { 
       repaint(); 
      } 
     }); 

     JButton btn = new JButton(new AbstractAction("load") { 
      @Override 
      public void actionPerformed(ActionEvent ev) { 
       try { 
        src = new ImageIcon(new URL(txt.getText())).getImage(); 
        rect = new Rectangle(src.getWidth(null), src.getHeight(null)); 
        raw = new BufferedImage(rect.width+20, rect.height+20, BufferedImage.TYPE_INT_ARGB); 
        raw.getGraphics().drawImage(src, 0, 0, null); 
        pack(); 
       } catch(Exception e) { 
        e.printStackTrace(); 
       } 
      } 
     }); 
     JPanel ori = new JPanel(new BorderLayout()); 
     ori.add(txt, BorderLayout.CENTER); 
     txt.setText("http://upload.wikimedia.org/wikipedia/en/d/d5/Transparent_google_logo.png"); 
     ori.add(btn, BorderLayout.EAST); 
     JPanel pnl = new JPanel() { 
      @Override 
      protected void paintComponent(Graphics g) { 
       if(raw != null && src != null){ 
        BufferedImage dst = new BufferedImage(rect.width+20, rect.height+20, BufferedImage.TYPE_INT_ARGB); 
        new MyEffect().applyEffect(raw, dst, rect.width+20, rect.height+20); 
        g.drawImage(dst, slider.getValue(), slider.getValue(), null); 
        g.drawImage(src, 0, 0, null); 
       } 
      } 
      @Override 
      public Dimension getPreferredSize() { 
       return new Dimension(rect.width+5,rect.height+5); 
      } 
     }; 

     setDefaultCloseOperation(EXIT_ON_CLOSE); 
     getContentPane().setLayout(new BorderLayout()); 
     getContentPane().setBackground(Color.WHITE); 
     getContentPane().add(ori, BorderLayout.NORTH); 
     getContentPane().add(pnl, BorderLayout.CENTER); 
     getContentPane().add(slider, BorderLayout.EAST); 
     pack(); 
    } 

    public static void main(String[] args) { 
     try { 
      for(UIManager.LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) { 
       if("Nimbus".equals(info.getName())) { 
        UIManager.setLookAndFeel(info.getClassName()); 
        break; 
       } 
      } 
     } catch(Exception system) { 
      system.printStackTrace(); 
     } 
     EventQueue.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       new Example().setVisible(true); 
      } 
     }); 
    } 

    enum EffectType { 
     UNDER, BLENDED, OVER 
    } 

    public class MyEffect { 

     protected Color color = Color.BLACK; 
     /** Opacity a float 0-1 for percentage */ 
     protected float opacity = 0.75f; 
     /** Angle in degrees between 0-360 */ 
     protected int angle = 135; 
     /** Distance in pixels */ 
     protected int distance = 5; 
     /** The shadow spread between 0-100 % */ 
     protected int spread = 0; 
     /** Size in pixels */ 
     protected int size  = 5; 

     protected ArrayCache getArrayCache() { 
      ArrayCache cache = (ArrayCache)AppContext.getAppContext().get(ArrayCache.class); 
      if(cache == null) { 
       cache = new ArrayCache(); 
       AppContext.getAppContext().put(ArrayCache.class, cache); 
      } 
      return cache; 
     } 

     protected class ArrayCache { 
      private SoftReference<int[]> tmpIntArray = null; 
      private SoftReference<byte[]> tmpByteArray1 = null; 
      private SoftReference<byte[]> tmpByteArray2 = null; 
      private SoftReference<byte[]> tmpByteArray3 = null; 

      protected int[] getTmpIntArray(int size) { 
       int[] tmp; 
       if(tmpIntArray == null || (tmp = tmpIntArray.get()) == null || tmp.length < size) { 
        // create new array 
        tmp = new int[size]; 
        tmpIntArray = new SoftReference<int[]>(tmp); 
       } 
       return tmp; 
      } 

      protected byte[] getTmpByteArray1(int size) { 
       byte[] tmp; 
       if(tmpByteArray1 == null || (tmp = tmpByteArray1.get()) == null || tmp.length < size) { 
        // create new array 
        tmp = new byte[size]; 
        tmpByteArray1 = new SoftReference<byte[]>(tmp); 
       } 
       return tmp; 
      } 

      protected byte[] getTmpByteArray2(int size) { 
       byte[] tmp; 
       if(tmpByteArray2 == null || (tmp = tmpByteArray2.get()) == null || tmp.length < size) { 
        // create new array 
        tmp = new byte[size]; 
        tmpByteArray2 = new SoftReference<byte[]>(tmp); 
       } 
       return tmp; 
      } 

      protected byte[] getTmpByteArray3(int size) { 
       byte[] tmp; 
       if(tmpByteArray3 == null || (tmp = tmpByteArray3.get()) == null || tmp.length < size) { 
        // create new array 
        tmp = new byte[size]; 
        tmpByteArray3 = new SoftReference<byte[]>(tmp); 
       } 
       return tmp; 
      } 
     } 

     Color getColor() { 
      return color; 
     } 

     void setColor(Color color) { 
      Color old = getColor(); 
      this.color = color; 
     } 

     float getOpacity() { 
      return opacity; 
     } 

     void setOpacity(float opacity) { 
      float old = getOpacity(); 
      this.opacity = opacity; 
     } 

     int getAngle() { 
      return angle; 
     } 

     void setAngle(int angle) { 
      int old = getAngle(); 
      this.angle = angle; 
     } 

     int getDistance() { 
      return distance; 
     } 

     void setDistance(int distance) { 
      int old = getDistance(); 
      this.distance = distance; 
     } 

     int getSpread() { 
      return spread; 
     } 

     void setSpread(int spread) { 
      int old = getSpread(); 
      this.spread = spread; 
     } 

     int getSize() { 
      return size; 
     } 

     void setSize(int size) { 
      int old = getSize(); 
      this.size = size; 
     } 

     EffectType getEffectType() { 
      return EffectType.UNDER; 
     } 

     BufferedImage applyEffect(BufferedImage src, BufferedImage dst, int w, int h) { 
      if(src == null || src.getType() != BufferedImage.TYPE_INT_ARGB) { 
       throw new IllegalArgumentException("Effect only works with " 
        + "source images of type BufferedImage.TYPE_INT_ARGB."); 
      } 
      if(dst != null && dst.getType() != BufferedImage.TYPE_INT_ARGB) { 
       throw new IllegalArgumentException("Effect only works with " 
        + "destination images of type BufferedImage.TYPE_INT_ARGB."); 
      } 
      // calculate offset 
      double trangleAngle = Math.toRadians(angle - 90); 
      int offsetX = (int)(Math.sin(trangleAngle) * distance); 
      int offsetY = (int)(Math.cos(trangleAngle) * distance); 
      // clac expanded size 
      int tmpOffX = offsetX + size; 
      int tmpOffY = offsetX + size; 
      int tmpW = w + offsetX + size + size; 
      int tmpH = h + offsetX + size; 
      // create tmp buffers 
      int[] lineBuf = getArrayCache().getTmpIntArray(w); 
      byte[] tmpBuf1 = getArrayCache().getTmpByteArray1(tmpW * tmpH); 
      Arrays.fill(tmpBuf1, (byte)0x00); 
      byte[] tmpBuf2 = getArrayCache().getTmpByteArray2(tmpW * tmpH); 
      // extract src image alpha channel and inverse and offset 
      Raster srcRaster = src.getRaster(); 
      for(int y = 0; y < h; y++) { 
       int dy = (y + tmpOffY); 
       int offset = dy * tmpW; 
       srcRaster.getDataElements(0, y, w, 1, lineBuf); 
       for(int x = 0; x < w; x++) { 
        int dx = x + tmpOffX; 
        tmpBuf1[offset + dx] = (byte)((lineBuf[x] & 0xFF000000) >>> 24); 
       } 
      } 
      // blur 
      float[] kernel = createGaussianKernel(size); 
      blur(tmpBuf1, tmpBuf2, tmpW, tmpH, kernel, size); // horizontal pass 
      blur(tmpBuf2, tmpBuf1, tmpH, tmpW, kernel, size);// vertical pass 
      //rescale 
      float spread = Math.min(1/(1 - (0.01f * this.spread)), 255); 
      for(int i = 0; i < tmpBuf1.length; i++) { 
       int val = (int)((tmpBuf1[i] & 0xFF) * spread); 
       tmpBuf1[i] = (val > 255) ? (byte)0xFF : (byte)val; 
      } 
      // create color image with shadow color and greyscale image as alpha 
      if(dst == null) { 
       dst = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); 
      } 
      WritableRaster shadowRaster = dst.getRaster(); 
      int red = color.getRed(), green = color.getGreen(), blue = color.getBlue(); 
      for(int y = 0; y < h; y++) { 
       int srcY = y + tmpOffY; 
       int shadowOffset = (srcY - offsetY) * tmpW; 
       for(int x = 0; x < w; x++) { 
        int srcX = x + tmpOffX; 
        lineBuf[x] = tmpBuf1[shadowOffset + (srcX - offsetX)] << 24 | red << 16 | green << 8 | blue; 
       } 
       shadowRaster.setDataElements(0, y, w, 1, lineBuf); 
      } 
      return dst; 
     } 
    } 

    static float[] createGaussianKernel(int radius) { 
     if(radius < 1) { 
      throw new IllegalArgumentException("Radius must be >= 1"); 
     } 

     float[] data = new float[radius * 2 + 1]; 

     float sigma = radius/3.0f; 
     float twoSigmaSquare = 2.0f * sigma * sigma; 
     float sigmaRoot = (float)Math.sqrt(twoSigmaSquare * Math.PI); 
     float total = 0.0f; 

     for(int i = -radius; i <= radius; i++) { 
      float distance = i * i; 
      int index = i + radius; 
      data[index] = (float)Math.exp(-distance/twoSigmaSquare)/sigmaRoot; 
      total += data[index]; 
     } 

     for(int i = 0; i < data.length; i++) { 
      data[i] /= total; 
     } 

     return data; 
    } 

    static void blur(byte[] srcPixels, byte[] dstPixels, int width, int height, float[] kernel, int radius) { 
     float p; 
     int cp; 
     for(int y = 0; y < height; y++) { 
      int index = y; 
      int offset = y * width; 
      for(int x = 0; x < width; x++) { 
       p = 0.0f; 
       for(int i = -radius; i <= radius; i++) { 
        int subOffset = x + i; 
        //     if (subOffset < 0) subOffset = 0; 
        //     if (subOffset >= width) subOffset = width-1; 
        if(subOffset < 0 || subOffset >= width) { 
         subOffset = (x + width) % width; 
        } 
        int pixel = srcPixels[offset + subOffset] & 0xFF; 
        float blurFactor = kernel[radius + i]; 
        p += blurFactor * pixel; 
       } 
       cp = (int)(p + 0.5f); 
       dstPixels[index] = (byte)(cp > 255 ? 255 : cp); 
       index += height; 
      } 
     } 
    } 
}