65.9K
CodeProject 正在变化。 阅读更多。
Home

Java Swing 中的任意形状透明 JFrame

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.67/5 (3投票s)

2010年10月10日

Apache

5分钟阅读

viewsIcon

62331

downloadIcon

4445

为自定义 JFrame 创建形状,并在 Windows 平台上为整个窗口应用透明效果(0 到 1 的 alpha 值)

引言

这项工作的目的是创建这个炫酷的窗口

screen1.PNG

我们在后面有一个 JFrame 副本,但具有炫酷的透明效果和圆角形状。困难之处在于重新创建窗口标题栏,带有标题和用于 window_state 的按钮。但本文可以澄清任何疑问。

图形包

我们目的的简单包的 UML 表示是

uml.PNG

RoundedWindow 是预览截图中的对象。包的基本组件是 ShapedFrame,这是 JFrame 的一个继承类,它能够修改其形状(从每个窗口的简单矩形形状,甚至到圆形),并在可能的情况下应用透明效果。

实现此目的的 JAVA 工具是 AWTUtilities,但这不是官方版本,因此我创建了一个 AWTUtilities 的包装器,具有最高级别的抽象,以便如果 AWTUtilities 被更改为另一个包,您只需修改 AWTUtilitiesWrapper 引用,而不是源代码中的所有出现。

由于 ShapedFrame 是基本继承,我们必须创建一个像“SHAPEX”Frame 这样的扩展,在我们的例子中是 RoundedRectFrame。此对象扩展了 ShapedFrame,能够设置透明度和形状,并且仅具有 alpha 值和基本形状管理。请参见下文。

最后有一个实用对象:VisualDragHandle。这是什么??首先,我需要说明自定义形状的 JFrame 必须是“未装饰的”,因此它没有用于在屏幕上拖动的句柄。所以这是一个对象,当鼠标点击它时,它能够拖动父窗口。唯一的要求是必须将其直接添加到 JFrame 的 contentPane

现在将对每个类进行简单的解释。

ShapedFrame

public abstract class ShapedFrame extends JFrame {

 protected Shape shape;
 protected float alpha = 1f;
 public ShapedFrame() {
        //If is DECORATED effects are disabled
        setUndecorated(true);
        setVisible(true);
        setListenersForEffects();
    }

 //.........................

 private void setListenersForEffects() {
        //It is important to upadate visual effect on form resize.
        addComponentListener(new ComponentAdapter() {

            @Override
            public void componentResized(ComponentEvent evt) {
                updateFrameEffects();
            }
        });
    }
 
 //.........................
 
 public void updateFrameEffects() {
        updateShape();
        try {
            AWTUtilitiesWrapper.setWindowShape(this, shape);
            if (shape != null) {
                AWTUtilitiesWrapper.setWindowOpacity(this, alpha);
            }
        } catch (Exception ex) {
            Logger.getLogger(ShapedFrame.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
  
 //.........................
} 

这不是整个类,而是最重要的方法。有一个设置 JFrame “UNDECORATE”状态和添加监听器的基本构造函数。updateFrameEffects 是此包高级图形的核心:它调用 AWTUtilities 的两个重要方法来实现透明度和形状。每次 JFrame 调整大小时都必须调用此方法。setListenersForEffects 将前一个方法链接到 resize 事件。

唯一的属性就是 alpha 和形状。

RoundedRectFrame

因为前一个类是 abstract (因为每种形状类型都有不同的行为),我们必须实现一个真实的形状类,如 RoundedRectFrame

public class RoundedRectFrame extends ShapedFrame {

    protected Dimension arcSize = new Dimension(50, 50);

    public RoundedRectFrame() {
        super(300, 200);
        setShapeToDefault();
    }

    public final void setShapeToDefault() {
        shape = new RoundRectangle2D.Double
	(0d, 0d, getWidth(), getHeight(), arcSize.width, arcSize.height);
    }

    @Override
    public void updateShape() {
        setShapeToDefault();
    }
}

省略 getter 和 setter,这是整个类。它非常简单,因为它只需要向父 abstract 类解释 RoundedRect 形状在我们要绘制它、调整它等方面时的行为……然后呢?它仅通过源 JFrame 的宽度和高度来调整 RoundedRect 的大小。特殊之处在于在 parent 类中声明 updateShape abstract ,这个方法将在 JFrame 更新自身时被调用;因此,通过重写此方法,我们将确保显示的形状是我们想要的。

RoundedWindow

此类是工作流程的终点。此类比较复杂,因此无法显示所有源代码。

public class RoundedWindow extends RoundedRectFrame {

    private JLabel titleLabel;
    private JPanel container;

    public RoundedWindow(JPanel defaultPanel) {
        super();
        super.setLayout(new BorderLayout());
        container = defaultPanel;
        addHeader();
        setTitle("Rounded Window");
    }

    private void addHeader() {
        titleLabel = new JLabel(getTitle());
        titleLabel.setForeground(Color.white);

        VisualDragHandle dragHandle = new VisualDragHandle(this);


        dragHandle.add(titleLabel);
        dragHandle.add(getIconifyComponent());
        dragHandle.add(getCloseComponent());

        super.add(dragHandle, BorderLayout.NORTH);
        super.add(container, BorderLayout.CENTER);
    }

	//............................
}

这只是类的基础。默认构造函数将 JPanel 作为参数,因为它创建一个自定义 JFrame,其中 contentPane 不是我们实际工作的窗格。正如您在第一个屏幕截图中看到的,RoundedWindow 由一个带有标题的 DarkGray 标题栏和一个带有图像作为容器的 JPanel 组成。实际上,这就是一个 JPanel。类其余部分是对 JFrame 组件管理方法的重写。例如:

@Override
    public Component add(Component comp) {
        if (container != null) {
            return container.add(comp);
        }
        return super.add(comp);
    }

为什么?一些用户已经理解了:在我们添加了一个自定义 JPanel 作为容器后,当我们向 JFrame 添加组件时,我们希望该组件被添加到 JPanel 中,而不是直接添加到 JFrame 中。如果您不理解,请写注释。

addHeader 方法是标题栏的创建。基本上,我们创建一个 VisualDragHandle,如前所述,并向这个 Handle(一个简单的 JPanel)添加几个元素,如标题和两个用于 Iconify Close 的对象。这些对象通过两个方法检索:getIconifyComponent getCloseComponent,这些方法创建两个自定义组件,在本例中是两个简单的 JLable 及其相关事件,并将它们返回给 addHeader 方法以添加到标题栏中。

其他

在源代码的主类中,有这个核心代码:

CustomPanel panel = new CustomPanel();
CustomPanel panel2 = new CustomPanel();
panel.setImage("glass.jpg");
panel2.setImage("glass.jpg");

//Standard JFrame creation
JFrame old = new JFrame();
old.setSize(700, 500);
old.setLayout(new BorderLayout());
old.add(panel2, BorderLayout.CENTER);
old.setVisible(true);

//New Cool Frame cration
final RoundedWindow roundedFrame = new RoundedWindow(panel);
roundedFrame.setSize(700, 500);
roundedFrame.setAlpha(0.9f);
roundedFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
roundedFrame.center();

CustomPanel 是一个简单的面板(带有 Dr.House 照片和数据:),我是用 netbeans 创建的,所以请忽略代码。特殊之处在于它继承自 ImagePanel,这是一个带有图像背景的简单 JPanel,请参阅有关 DraggableImageComponent 的文章,它几乎是相同的。之所以继承,是因为我想要一个炫酷的玻璃背景为我的窗口。

主代码然后使用这个自定义组件创建两个框架:一个简单的 JFrame 和一个 RoundedWindow 框架。您可以在第一个屏幕截图中看到这两个 JFrames 之间的视觉差异。

结论

现在您有了一个可重用的组件,如 RoundedWindow,用于创建具有透明效果和圆角的简单小型窗口。虽然您可以扩展 ShapedFrame 来创建自定义形状,如:椭圆、圆形或折线,只需遵循 RoundedRectFrame 的方式即可。如果您想要(……只需简单投票!!!:)我可以发布我关于多种 JFrames 形状的工作,用于创建类似半透明时钟或日历等的窗口小部件。

必备组件

现在我已在以下平台上测试了此工作:

  • Windows Vista
  • Windows 7

JRE 的构建版本是 jre1.6.0_17,目前在 Linux GNOME 桌面下无法正常工作。我没有在 KDE 上测试过。所以如果您测试过,请告诉我。

© . All rights reserved.