Exploring JDK 7, Part 2: Translucent and Shaped Windows
Oracle’s release of JDK 7 is expected to occur this coming fall. This new release will offer a suite of new features for you to learn.
This article, the second in a four-part series that introduces you to some of these features (read Part 1 here, focuses on JDK 7’s improved support for translucent and shaped windows.
Java SE 6u10 (build 12) introduced com.sun.awt.AWTUtilities to support translucent and shaped windows. This temporary class was introduced because 6u10 wasn't a major Java SE release; no new Abstract Window Toolkit APIs could be added or existing APIs modified.
AWTUtilities doesn't exist in JDK 7. Instead, the necessary changes have been made to various AWT classes to support translucent and shaped windows. This article examines the AWT's three kinds of translucency support, and also examines its support for shaped windows.
Simple Translucency
Simple translucency results in an evenly translucent window; all pixels have the same opacity value. The smaller this value, the more translucent the window until it becomes transparent; the larger this value, the less translucent the window until it becomes opaque.
JDK 7 supports simple translucency by adding public void setOpacity(float opacity) and public float getOpacity() methods to the java.awt.Window class. The former method requires an opacity argument ranging from 0.0 (transparent) to 1.0 (opaque).
Invoke setOpacity() to activate simple translucency for the window on which this method is invoked. Don't specify an argument that is less than 0.0 or greater than 1.0; otherwise, setOpacity() will throw IllegalArgumentException.
The setOpacity() method also throws java.awt.IllegalComponentStateException if the window is in full-screen mode and the opacity is less than 1.0, and UnsupportedOperationException if simple translucency isn't supported and the opacity is less than 1.0.
The java.awt.GraphicsDevice class provides a public Window getFullScreenWindow() method for determining if the window is in full-screen mode. This class also provides the following method for determining if the current graphics device supports simple translucency:
public boolean isWindowTranslucencySupported(GraphicsDevice.WindowTranslucency translucencyKind)
The isWindowTranslucencySupported() method returns true if the kind of translucency specified by its argument is supported. For simple translucency, this argument must be GraphicsDevice.WindowTranslucency.TRANSLUCENT, as demonstrated below:
GraphicsEnvironment ge; ge = GraphicsEnvironment.getLocalGraphicsEnvironment (); if (!ge.getDefaultScreenDevice (). isWindowTranslucencySupported (GraphicsDevice.WindowTranslucency.TRANSLUCENT)) { System.err.println ("simple translucency isn't supported"); return; }
I've created a STDemo application that demonstrates simple translucency. Use its user interface's (UI's) slider component to adjust its frame window opacity from opaque to transparent (at which point the window disappears). Listing 1 presents the application's source code.
Listing 1STDemo.java
// STDemo.java import java.awt.EventQueue; import java.awt.FlowLayout; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JSlider; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; public class STDemo extends JFrame { public STDemo () { super ("Simple Translucency Demo"); setDefaultCloseOperation (EXIT_ON_CLOSE); final JSlider slider = new JSlider (0, 100, 100); ChangeListener cl; cl = new ChangeListener () { public void stateChanged (ChangeEvent ce) { JSlider source = (JSlider) ce.getSource (); STDemo.this.setOpacity (source.getValue ()/100.0f); } }; slider.addChangeListener (cl); getContentPane ().setLayout (new FlowLayout ()); getContentPane ().add (new JLabel ("TRANSP")); getContentPane ().add (new JPanel () {{ add (slider); }}); getContentPane ().add (new JLabel ("OPAQUE")); getRootPane ().setDoubleBuffered (false); pack (); 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. TRANSLUCENT)) { System.err.println ("simple translucency isn't "+ "supported"); return; } new STDemo (); } }; EventQueue.invokeLater (r); } }
Listing 1 creates a slider and registers a change listener with this component. While the slider control moves, this component fires change events to the listener, which responds by invoking setOpacity() with the slider's current value converted to [0.0, 1.0].
The listing takes advantage of the new JPanel () {{ add (slider); }} shortcut to create a Swing panel and add the slider component to the panel. Essentially, this shortcut instantiates a subclass of JPanel and uses the subclass's instance initializer to add the slider.
Swing's component double buffering yields an unexpected visual artifact where an opaque slider image is left behind when you drag the translucent frame window. Listing 1 disables double buffering, via getRootPane ().setDoubleBuffered (false);, to avoid this artifact.
Compile Listing 1; then run STDemo. Adjusting the slider results in a translucent window and translucent slider (see Figure 1). Don't release the mouse button once you reach transparent; otherwise, you won't be able to revert to translucent and opaque.
Figure 1 The window and its contents are evenly translucent.