技术开发 频道

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

  像素级透明和任意形状的窗口

  像素级透明和像素级半透明类似,这种半透明模式主要用于任意形状窗口中的内容。

  任意形状窗口是未加装饰的窗口,其外观与特定几何形状一致(如圆,圆角矩形等),形状外的像素是透明的,在这些像素上点击才显示背景。

  JDK 7通过向Window增加public void setShape(Shape shape)和public Shape getShape()方法支持像素级透明和任意形状的窗口,向前一个方法传递一个java.awt.Shape实例给当前窗口指定一个形状。

  如果窗口处于全屏模式且传递来一个非空形状时,setShape()方法会抛出IllegalComponentStateException异常,如果不支持像素级透明且传递来一个非空形状时,抛出UnsupportedOperationException异常。

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

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

  我创建了一个PPTSWDemo程序演示像素级透明和任意形状的窗口,我们将清单2中显示出来的圆角矩形改成椭圆形状,清单3显示了这个程序的源代码。

  清单3. PPTSWDemo.java

// PPTSWDemo.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.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class PPTSWDemo extends JFrame
{
  
public PPTSWDemo ()
   {
      
super ("Per-Pixel Transparency and Shaped Window Demo");
      setUndecorated (
true); // Avoid decorated window artifacts.
      JPanel gradPanel = new JPanel ()
                         {
                            
// Solid white
                             Color colorA = new Color (255, 255, 255);
                            
// Solid red
                             Color colorB = new Color (255, 0, 0);
                            
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);
      pack ();
      setShape (
new Ellipse2D.Float (0, 0, getWidth (), getHeight ()));
      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_TRANSPARENT))
                 {
                     System.err.println (
"per-pixel transparency isn't "+
                                        
"supported");
                    
return;
                 }
                
new PPTSWDemo ();
              }
          };
      EventQueue.invokeLater (r);
   }
}

  在验证了支持像素级透明后,清单3执行setShape (new Ellipse2D.Float (0, 0, getWidth (), getHeight ()));将框架窗口改成椭圆形,效果如图3所示。

 像素级透明和任意形状的窗口

图 3 梯度式透明现在限制在椭圆范围内

  遗憾的是,任意形状窗口的边缘有锯齿,也许等到JDK 7正式发布,使用像素级半透明和抗锯齿功能可以解决掉这个问题。

0
相关文章