技术开发 频道

JDK 7探秘二:半透明和任意形状的窗口

  像素级半透明窗口

  像素级半透明允许你控制窗口中每个像素的不透明度,这样就可以营造出窗口的一部分比另一部分更透明的效果,虽然像素级半透明也可以实现窗口透明度均匀,但与简单半透明方法比起来,它更占资源。

  JDK 7通过修改Window的public void setBackground(Color bgColor)方法,检查参数的alpha部分提供像素级半透明效果的支持,如果alpha不等于1.0(窗口不透明),在窗口上绘制每个像素时将会使用alpha值。

  真实的半透明级别

  绘制像素时使用的真实半透明值也依赖于传递给Window的setOpacity()方法的值,以及Window的当前形状。

  如果窗口处于全屏模式且背景色的alpha值小于1.0,这个方法将会抛出IllegalComponentStateException异常,如果不支持像素级半透明且alpha值小于1.0,将会抛出UnsupportedOperationException异常。

  为了避免后一个异常,调用GraphicsDevice's isWindowTranslucencySupported()方法时,参数必须使用GraphicsDevice.WindowTranslucency.PERPIXEL_TRANSLUCENT,并检查返回的值,如下所示:

GraphicsEnvironment ge;
ge
= GraphicsEnvironment.getLocalGraphicsEnvironment ();
if (!ge.getDefaultScreenDevice ().
        isWindowTranslucencySupported (GraphicsDevice.WindowTranslucency.PERPIXEL_TRANSLUCENT))
{
    System.err.println (
"per-pixel translucency isn't supported");
    
return;
}

  另外,确定窗口本身是否支持像素级半透明效果也很重要,可调用java.awt.GraphicsConfiguration's public Boolean isTranslucencyCapable()方法来判断,如果支持的话,这个方法返回Ture,如下所示

/ The following code fragment continues from the previous code fragment, but assumes that
// the current class is a descendent of java.awt.Window.
if (!getGraphicsConfiguration ().isTranslucencyCapable ())
{
    System.err.println (
"per-pixel translucency not in effect for this graphics configuration");
    System.exit (
0);
}

  如果你想确定当前背景色的alpha,可调用Window的public Color getBackground()方法,你也可以调用新的public boolean isOpaque()方法确定窗口当前是否是不透明的(返回True)。

  我创建了一个PPTDemo程序演示像素级半透明窗口,清单2显示了它的代码,因为这个窗口是未加装饰的,你需要点击它的关闭按钮来终止它。

  清单2. PPTDemo.java

// PPTDemo.java
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class PPTDemo extends JFrame
{
  
public PPTDemo ()
   {
      
super ("Per-Pixel Translucency Demo");
      JPanel gradPanel
= new JPanel ()
                         {
                            
// Transparent red
                             Color colorA = new Color (255, 0, 0, 0);
                            
// Solid red
                             Color colorB = new Color (255, 0, 0, 255);
                            
protected void paintComponent (Graphics g)
                             {
                                 Graphics2D g2d
= (Graphics2D) g;
                                 GradientPaint gp;
                                 gp
= new GradientPaint (0.0f, 0.0f, colorA,
                                                        
0.0f, getHeight (),
                                                         colorB,
true);
                                 g2d.setPaint (gp);
                                 g2d.fillRect (
0, 0, getWidth (),
                                               getHeight ());
                                
                             }
                         };
      gradPanel.setPreferredSize (
new Dimension (300, 200));
      gradPanel.setLayout (
new BoxLayout (gradPanel, BoxLayout.Y_AXIS));
      JButton btnClose
= new JButton ("Close");
      ActionListener al;
      al
= new ActionListener ()
           {
              
public void actionPerformed (ActionEvent ae)
               {
                  System.exit (
0);
               }
           };
      btnClose.addActionListener (al);
      btnClose.setAlignmentX (
0.5f);
      gradPanel.add (Box.createVerticalGlue ());
      gradPanel.add (btnClose);
      gradPanel.add (Box.createVerticalGlue ());
      setContentPane (gradPanel);
      
if (!getGraphicsConfiguration ().isTranslucencyCapable ())
      {
          System.err.println (
"per-pixel translucency not in effect for "+
                              
"this graphics configuration");
          System.exit (
0);
      }
      setBackground (
new Color (0, 0, 0, 0)); // Achieve per-pixel
                                              
// translucency.
      pack ();
      setLocationRelativeTo (
null);
      setVisible (
true);
   }
  
public static void main (String [] args)
   {
      Runnable r;
      r
= new Runnable ()
          {
              
public void run ()
              {
                 GraphicsEnvironment ge;
                 ge
= GraphicsEnvironment.getLocalGraphicsEnvironment ();
                
if (!ge.getDefaultScreenDevice ().
                         isWindowTranslucencySupported
                           (GraphicsDevice.WindowTranslucency.
                                           PERPIXEL_TRANSLUCENT))
                 {
                     System.err.println (
"per-pixel translucency isn't "+
                                        
"supported");
                    
return;
                 }
                
new PPTDemo ();
              }
          };
      EventQueue.invokeLater (r);
   }
}

  上面的代码显示了用JPanel类创建了两个java.awt.Color对象,alpha值为0时透明,为255时不透明,它的paintComponent()方法和java.awt.GradientPaint一起给面板的表面涂上了一层梯度式alpha值。

  后面的代码将这个面板作为框架窗口的内容面板,并验证窗口的图形配置是否支持像素级半透明,最后调用setBackground()方法开启像素级半透明窗口效果。

  调整窗口的大小后,清单2中的代码调用setLocationRelativeTo(null)让面板在屏幕上居中,接着调用setVisible(true)方法控制面板的半透明显示:上方透明,下方不透明,中间半透明,如图2所示。

 像素级半透明窗口

图 2 从上到下,透明度不断减小

0
相关文章