2013-03-09 189 views
0

我正在尝试使JPanel透明,但我无法完成它的工作。是否有可能做到这一点?如何绘制透明背景?

import java.awt.*; 
import javax.swing.*; 

public class ClearPanel extends JPanel{ 
public static void main(String[] args) { 
    ClearPanel c = new ClearPanel(); 
    c.setPreferredSize(new Dimension(200, 200)); 
    c.setOpaque(false); 

    JPanel backPanel = new JPanel(); 
    backPanel.setBackground(Color.CYAN); 

    backPanel.add(c); 

    JFrame f = new JFrame(); 
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    f.setContentPane(backPanel); 
    f.pack(); 
    f.setLocationRelativeTo(null); 
    f.setVisible(true); 
} 

@Override 
protected void paintComponent(Graphics g) { 
    super.paintComponent(g); 
    g.fillOval(0, 0, 200, 200); 
    g.clearRect(45, 45, 50, 50); 

    Graphics2D g2 = (Graphics2D) g; 
    g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.0f)); 
    g2.fillRect(75, 75, 50, 50); 
} 
} 

椭圆应该是不透明的,但我想要透明的矩形。通过透明,我的意思是我应该能够看到ClearPanel背后的面板。

从MadProgrammer的回答开始,是否有任何方法可以将灰色方块绘制在区域之外,但在区域内保持透明?

@Override 
    protected void paintComponent(Graphics g) { 
     super.paintComponent(g); 
     Rectangle fill = new Rectangle(getWidth(), getHeight()); 
     Graphics2D g2d = (Graphics2D) g.create(); 

     Rectangle hole = new Rectangle(0, 0, 100, 100); 

     Area area = new Area(fill); 
     area.subtract(new Area(hole)); 
     g2d.setColor(getBackground()); 
     g2d.fill(area); 

     g2d.setColor(Color.RED); 
     g2d.setComposite(AlphaComposite.SrcOver.derive(0.0f)); 
     g2d.fill(hole); 

     g2d.setComposite(AlphaComposite.SrcOver.derive(1.0f)); 
     g2d.setColor(Color.DARK_GRAY); 
     if(area.contains(0,0,100,200)) 
      g2d.fillRect(0, 0, 100, 200); 

     g2d.dispose();  
    } 
+0

没有'drawRect()'满足您的需求? – uba 2013-03-09 10:24:01

+0

@uba不,因为我无法透过Jpanel看到,我仍然会看到矩形绘制的椭圆。 – 2013-03-09 10:25:55

+0

*“我试图让一片JPanel透明..”*为什么它提供了什么应用程序功能?我问,因为有可能有更好的方法来实现这一功能。 – 2013-03-09 12:38:50

回答

4

你的问题是,默认情况下,JPanel是不透明的,这意味着重绘不会在它画什么。

您需要将面板设置为透明,然后接管背景的绘制。

现在,真正的技巧开始。如果您只是简单地填充组件,然后尝试在其顶部绘制透明部分,则只需在不透明背景上绘制透明部分...并不是很有帮助。

你需要做的不是填充你想保持透明的区域。

您可以通过使用Area形状来完成此操作,该形状具有能够附加/添加和删除形状的巧妙技巧。

enter image description here

import java.awt.AlphaComposite; 
import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.EventQueue; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.Rectangle; 
import java.awt.geom.Area; 
import java.awt.geom.Ellipse2D; 
import java.awt.image.BufferedImage; 
import java.io.File; 
import java.io.IOException; 
import java.util.logging.Level; 
import java.util.logging.Logger; 
import javax.imageio.ImageIO; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.UIManager; 
import javax.swing.UnsupportedLookAndFeelException; 

public class TransparentPane { 

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

    public TransparentPane() { 
     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) { 
       } 

       BackgroundPane backgroundPane = new BackgroundPane(); 
       backgroundPane.setBackground(Color.RED); 
       backgroundPane.setLayout(new BorderLayout()); 
       backgroundPane.add(new TranslucentPane()); 

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

    public class BackgroundPane extends JPanel { 

     private BufferedImage bg; 

     public BackgroundPane() { 
      try { 
       bg = ImageIO.read(new File("/path/to/your/image.jpg")); 
      } catch (IOException ex) { 
       ex.printStackTrace(); 
      } 
     } 

     @Override 
     public Dimension getPreferredSize() { 
      return bg == null ? super.getPreferredSize() : new Dimension(bg.getWidth(), bg.getHeight()); 
     } 

     @Override 
     protected void paintComponent(Graphics g) { 
      super.paintComponent(g); 
      if (bg != null) { 
       int width = getWidth() - 1; 
       int height = getHeight() - 1; 
       int x = (width - bg.getWidth())/2; 
       int y = (height - bg.getHeight())/2; 
       g.drawImage(bg, x, y, this); 
      } 
     } 

    } 

    public class TranslucentPane extends JPanel { 

     public TranslucentPane() { 
      setOpaque(false); 
     } 

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

     @Override 
     protected void paintComponent(Graphics g) { 
      super.paintComponent(g); 
      Rectangle fill = new Rectangle(getWidth(), getHeight()); 
      Graphics2D g2d = (Graphics2D) g.create(); 

      int width = getWidth() - 1; 
      int height = getHeight() - 1; 
      int radius = Math.min(width, height)/2; 
      int x = (width - radius)/2; 
      int y = (height - radius)/2; 

      Ellipse2D hole = new Ellipse2D.Float(x, y, radius, radius); 

      Area area = new Area(fill); 
      area.subtract(new Area(hole)); 
      g2d.setColor(getBackground()); 
      g2d.fill(area); 

      g2d.setColor(Color.RED); 
      g2d.setComposite(AlphaComposite.SrcOver.derive(0.25f)); 
      g2d.fill(hole); 

      g2d.dispose(); 
     } 

    } 

} 

更新

嗯,这花了一点时间越长,我的预期......

enter image description here

基本上,我们需要创建的面具然后,从我们想要显示的矩形中减去孔的形状从我们想要显示的矩形中减去那个结果

import java.awt.AlphaComposite; 
import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.EventQueue; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.Rectangle; 
import java.awt.geom.Area; 
import java.awt.geom.Ellipse2D; 
import java.awt.image.BufferedImage; 
import java.io.File; 
import java.io.IOException; 
import java.util.logging.Level; 
import java.util.logging.Logger; 
import javax.imageio.ImageIO; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.UIManager; 
import javax.swing.UnsupportedLookAndFeelException; 

public class TransparentPane { 

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

    public TransparentPane() { 
     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) { 
       } 

       BackgroundPane backgroundPane = new BackgroundPane(); 
       backgroundPane.setBackground(Color.RED); 
       backgroundPane.setLayout(new BorderLayout()); 
       backgroundPane.add(new TranslucentPane()); 

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

    public class BackgroundPane extends JPanel { 

     private BufferedImage bg; 

     public BackgroundPane() { 
      try { 
       bg = ImageIO.read(new File("/Users/swhitehead/Dropbox/MegaTokyo/Evil_Small.jpg")); 
      } catch (IOException ex) { 
       ex.printStackTrace(); 
      } 
     } 

     @Override 
     public Dimension getPreferredSize() { 
      return bg == null ? super.getPreferredSize() : new Dimension(bg.getWidth(), bg.getHeight()); 
     } 

     @Override 
     protected void paintComponent(Graphics g) { 
      super.paintComponent(g); 
      if (bg != null) { 
       int width = getWidth() - 1; 
       int height = getHeight() - 1; 
       int x = (width - bg.getWidth())/2; 
       int y = (height - bg.getHeight())/2; 
       g.drawImage(bg, x, y, this); 
      } 
     } 

    } 

    public class TranslucentPane extends JPanel { 

     public TranslucentPane() { 
      setOpaque(false); 
     } 

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

     @Override 
     protected void paintComponent(Graphics g) { 
      super.paintComponent(g); 
      Rectangle fill = new Rectangle(getWidth(), getHeight()); 
      Graphics2D g2d = (Graphics2D) g.create(); 

      int width = getWidth() - 1; 
      int height = getHeight() - 1; 
      int radius = Math.min(width, height)/2; 
      int x = (width - radius)/2; 
      int y = (height - radius)/2; 

      Ellipse2D hole = new Ellipse2D.Float(x, y, radius, radius); 

      Area area = new Area(fill); 
      area.subtract(new Area(hole)); 
      g2d.setColor(getBackground()); 
      g2d.fill(area); 

      g2d.setColor(Color.RED); 
      g2d.setComposite(AlphaComposite.SrcOver.derive(0.0f)); 
      g2d.fill(hole); 
      g2d.dispose(); 

      g2d = (Graphics2D) g.create(); 

      // Basically, we create an area that is subtraction of the window/rectangle 
      // from the whole. This leaves us with a rectangle (with a hole in it) 
      // that doesn't include the area where the whole is... 
      Rectangle win = new Rectangle(
          x + (radius/2), 
          y + (radius/2), radius, (radius/4)); 
      area = new Area(win); 
      area.subtract(new Area(hole)); 

      // Then we create a area that is a subtraction of the original rectangle 
      // from the one with a "hole" in it... 
      Area actual = new Area(win); 
      actual.subtract(area); 
      g2d.setColor(Color.BLUE); 
      g2d.setComposite(AlphaComposite.SrcOver.derive(0.5f)); 
      g2d.fill(actual); 

      g2d.dispose(); 
     }   
    } 
} 
+0

感谢您的回答,我已更新我的问题,如果你也想看看。再次感谢。 – 2013-03-09 11:39:45

+0

更改AlphaComposite类型。你也可以从矩形的区域开始(重叠),从透明部分减去,填充为不透明,然后,从相同区域开始,减去透明区域以外的区域并填充该区域... – MadProgrammer 2013-03-09 20:11:09

+0

检查更新... – MadProgrammer 2013-03-10 07:08:12