像素级半透明窗口
像素级半透明允许你控制窗口中每个像素的不透明度,这样就可以营造出窗口的一部分比另一部分更透明的效果,虽然像素级半透明也可以实现窗口透明度均匀,但与简单半透明方法比起来,它更占资源。
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,并检查返回的值,如下所示:
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 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
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 从上到下,透明度不断减小