文档

Java™ 教程
隐藏目录
如何创建半透明和有形状的窗口
路径:使用Swing创建GUI
课程:使用其他Swing功能

如何创建透明和有形状的窗口

从Java平台标准版6(Java SE 6)更新10版本开始,您可以在Swing应用程序中添加半透明和形状窗口。本页面涵盖以下主题:

支持的功能

这个功能是JDK 7版本中公共AWT包的一部分,有以下三种形式:

确定平台的能力

UnsupportedOperationExceptionsetShapesetOpacityGraphicsDeviceisWindowTranslucencySupported(GraphicsDevice.WindowTranslucency)GraphicsDevice.WindowTranslucency GraphicsConfigurationisTranslucencyCapablePERPIXEL_TRANSLUCENTGraphicsConfiguration

版本说明: 半透明和形状窗口的API首次添加到Java SE 6 Update 10版本中作为私有API。此功能在JDK 7版本中移至公共AWT包。本教程描述了JDK 7版本中可用的API。请参阅Java SE 6 Update 10 API,了解Java SE 6 Update 10版本中的私有API与JDK 7版本中的公共API的对应关系。
import static java.awt.GraphicsDevice.WindowTranslucency.*;

// 确定默认的GraphicsDevice支持的能力。
GraphicsEnvironment ge =
    GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice gd = ge.getDefaultScreenDevice();

boolean isUniformTranslucencySupported =
    gd.isWindowTranslucencySupported(TRANSLUCENT);
boolean isPerPixelTranslucencySupported =
    gd.isWindowTranslucencySupported(PERPIXEL_TRANSLUCENT);
boolean isShapedWindowSupported =
    gd.isWindowTranslucencySupported(PERPIXEL_TRANSPARENT);

注意: 这些能力都无法在全屏模式下工作。在全屏模式下调用任何相关方法会导致抛出IllegalComponentStateException异常。

如何实现统一半透明度

setOpacity(float)WindowfloatgetOpacity

TranslucentWindowDemo.java示例创建了一个透明度为55%(半透明度为45%)的窗口。如果底层平台不支持半透明窗口,则示例会退出。与透明度相关的代码以粗体显示。

import java.awt.*;
import javax.swing.*;
import static java.awt.GraphicsDevice.WindowTranslucency.*;

public class TranslucentWindowDemo extends JFrame {
    public TranslucentWindowDemo() {
        super("TranslucentWindow");
        setLayout(new GridBagLayout());

        setSize(300,200);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //添加一个示例按钮。
        add(new JButton("我是一个按钮"));
    }

    public static void main(String[] args) {
        //确定GraphicsDevice是否支持半透明性。
        GraphicsEnvironment ge = 
            GraphicsEnvironment.getLocalGraphicsEnvironment();
        GraphicsDevice gd = ge.getDefaultScreenDevice();

        //如果不支持半透明窗口,则退出。
        if (!gd.isWindowTranslucencySupported(TRANSLUCENT)) {
            System.err.println(
                "不支持半透明性");
                System.exit(0);
        }
        
        JFrame.setDefaultLookAndFeelDecorated(true);

        //在事件分派线程上创建GUI
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                TranslucentWindowDemo tw = new TranslucentWindowDemo();

                //将窗口设置为55%的不透明度(45%的半透明度)。
                tw.setOpacity(0.55f);

                //显示窗口。
                tw.setVisible(true);
            }
        });
    }
}

请注意,按钮也受到均匀半透明性的影响。设置不透明度会影响整个窗口,包括窗口中包含的任何组件。

如何实现像素级半透明

GradientPaint

在窗口上调用setBackground(new Color(0,0,0,0))会导致软件使用alpha值来渲染像素级半透明性。实际上,调用setBackground(new Color(0,0,0,alpha),其中alpha小于255,会安装像素级透明度。因此,如果调用setBackground(new Color(0,0,0,128))并且不做其他操作,窗口将以每个背景像素50%的半透明度渲染。然而,如果您正在创建自己的alpha值范围,您可能希望使用alpha值为0。

尽管公共API没有禁止,但通常您会希望在无装饰窗口上启用每像素半透明性。在大多数情况下,使用装饰窗口的每像素半透明性是没有意义的。这样做可能会禁用装饰或引起其他平台相关的副作用。

要确定窗口是否使用每像素半透明性,可以使用isOpaque方法。

以下是一个示例。首先,这里是实现示例所需的步骤:

  1. 在窗口上调用setBackground(new Color(0,0,0,0))
  2. 创建一个覆盖paintComponent方法的JPanel实例。
  3. paintComponent方法中创建一个GradientPaint实例。
  4. 在示例中,矩形的顶部alpha值为0(最透明),底部alpha值为255(最不透明)。GradientPaint类会平滑地插值矩形顶部到底部的alpha值。
  5. GradientPaint实例设置为面板的绘制方法。

以下是GradientTranslucentWindowDemo.java示例的代码。如果底层平台不支持每像素半透明性,则该示例会退出。与创建渐变窗口相关的代码以粗体显示。

import java.awt.*;
import javax.swing.*;
import static java.awt.GraphicsDevice.WindowTranslucency.*;

public class GradientTranslucentWindowDemo extends JFrame {
    public GradientTranslucentWindowDemo() {
        super("GradientTranslucentWindow");

        setBackground(new Color(0,0,0,0));
        setSize(new Dimension(300,200));
        setLocationRelativeTo(null);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JPanel panel = new JPanel() {
            @Override
            protected void paintComponent(Graphics g) {
                if (g instanceof Graphics2D) {
                    final int R = 240;
                    final int G = 240;
                    final int B = 240;

                    Paint p =
                        new GradientPaint(0.0f, 0.0f, new Color(R, G, B, 0),
                            0.0f, getHeight(), new Color(R, G, B, 255), true);
                    Graphics2D g2d = (Graphics2D)g;
                    g2d.setPaint(p);
                    g2d.fillRect(0, 0, getWidth(), getHeight());
                }
            }
        };
        setContentPane(panel);
        setLayout(new GridBagLayout());
        add(new JButton("我是一个按钮"));
    }

    public static void main(String[] args) {
        // 确定GraphicsDevice的支持情况。
        GraphicsEnvironment ge = 
            GraphicsEnvironment.getLocalGraphicsEnvironment();
        GraphicsDevice gd = ge.getDefaultScreenDevice();
        boolean isPerPixelTranslucencySupported = 
            gd.isWindowTranslucencySupported(PERPIXEL_TRANSLUCENT);

        //如果不支持透明窗口,退出。
        if (!isPerPixelTranslucencySupported) {
            System.out.println(
                "不支持逐像素半透明");
                System.exit(0);
        }

        JFrame.setDefaultLookAndFeelDecorated(true);

        // 在事件分派线程上创建GUI
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                GradientTranslucentWindowDemo gtw = new
                    GradientTranslucentWindowDemo();

                // 显示窗口。
                gtw.setVisible(true);
            }
        });
    }
}

请注意,按钮不受逐像素半透明的影响。设置逐像素半透明只会影响背景像素。如果您想要窗口仅对背景像素产生均匀的半透明效果,可以调用setBackground(new Color(0,0,0,alpha)),其中alpha指定所需的半透明度。

如何实现一个自定义形状的窗口

setShape(Shape)WindowShape

设置窗口形状的最佳实践是在组件事件监听器的componentResized方法中调用setShape。这种做法将确保为窗口的实际大小正确计算形状。下面的示例使用了这种方法。

这个示例创建了一个椭圆形的窗口,透明度为70%。如果底层平台不支持窗口形状,示例会退出。如果底层平台不支持半透明,示例会使用标准的不透明窗口。你可以修改这个示例来创建一个同时使用逐像素半透明的窗口。

与窗口形状相关的代码以粗体显示。

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.geom.Ellipse2D;
import static java.awt.GraphicsDevice.WindowTranslucency.*;

public class ShapedWindowDemo extends JFrame {
    public ShapedWindowDemo() {
        super("ShapedWindow");
        setLayout(new GridBagLayout());

        // 最佳实践是在componentResized方法中设置窗口的形状。
        // 这样,如果窗口大小发生变化,形状将被正确地重新计算。
        addComponentListener(new ComponentAdapter() {
            // 给窗口设置椭圆形状。
            // 如果窗口大小改变,形状将在此处重新计算。
            @Override
            public void componentResized(ComponentEvent e) {
                setShape(new Ellipse2D.Double(0,0,getWidth(),getHeight()));
            }
        });

        setUndecorated(true);
        setSize(300,200);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        add(new JButton("我是一个按钮"));
    }

    public static void main(String[] args) {
        // 确定GraphicsDevice可以支持什么。
        GraphicsEnvironment ge = 
            GraphicsEnvironment.getLocalGraphicsEnvironment();
        GraphicsDevice gd = ge.getDefaultScreenDevice();
        final boolean isTranslucencySupported = 
            gd.isWindowTranslucencySupported(TRANSLUCENT);

        // 如果不支持窗口形状,退出。
        if (!gd.isWindowTranslucencySupported(PERPIXEL_TRANSPARENT)) {
            System.err.println("不支持窗口形状");
            System.exit(0);
        }

        // 如果不支持半透明窗口,创建一个不透明窗口。
        if (!isTranslucencySupported) {
            System.out.println(
                "不支持半透明窗口,创建一个不透明窗口");
        }

        // 在事件分派线程上创建GUI
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                ShapedWindowDemo sw = new ShapedWindowDemo();

                // 如果支持半透明,将窗口设置为70%透明度。
                if (isTranslucencySupported) {
                    sw.setOpacity(0.7f);
                }

                // 显示窗口。
                sw.setVisible(true);
            }
        });
    }
}

Java SE 6 更新 10 API

com.sun.awt.AWTUtilities
Java SE 6 更新 10 中的方法 JDK 7 的对应方法
AWTUtilities.isTranslucencySupported(Translucency) GraphicsDevice.isWindowTranslucencySupported(WindowTranslucency)
AWTUtilities.isTranslucencyCapable(GraphicsConfiguration) GraphicsConfiguration.isTranslucencyCapable()
AWTUtilities.setWindowOpacity(Window, float) Window.setOpacity(float)
AWTUtilities.setWindowShape(Window, Shape) Window.setShape(Shape)
AWTUtilities.setWindowOpaque(boolean) Window.setBackground(Color)new Color(0,0,0,alpha) 传递给此方法,其中 alpha 小于 255,可安装像素级半透明。

上一页: 如何与桌面类集成
下一页: 如何使用JLayer类装饰组件