- Simple Translucency
- Per-Pixel Translucency
- Per-Pixel Transparency and Shaped Windows
- Combining Translucency with Per-Pixel Transparency and Shaped Windows
- Conclusion
Per-Pixel Transparency and Shaped Windows
Per-pixel transparency is similar to per-pixel translucency, except for each window pixel's opacity being restricted to 0.0 (transparent) or 1.0 (opaque). This translucency mode is used in the context of shaped windows.
A shaped window is an undecorated window whose appearance conforms to a specific shape (such as a circle or a rectangle with rounded corners). Pixels outside of the shape are transparent and reveal the background[md]clicking on these pixels achieves nothing.
JDK 7 supports per-pixel transparency and shaped windows by adding public void setShape(Shape shape) and public Shape getShape() methods to Window. Pass a java.awt.Shape instance to the former method to give the current window a specific shape.
The setShape() method throws IllegalComponentStateException if the window is in full-screen mode and a non-null shape is passed, and UnsupportedOperationException if per-pixel transparency isn't supported and a non-null shape is passed.
To avoid the latter exception, call GraphicsDevice's isWindowTranslucencySupported() method with argument GraphicsDevice.WindowTranslucency.PERPIXEL_TRANSPARENT, and check the return value, as follows:
GraphicsEnvironment ge; ge = GraphicsEnvironment.getLocalGraphicsEnvironment (); if (!ge.getDefaultScreenDevice (). isWindowTranslucencySupported (GraphicsDevice.WindowTranslucency.PERPIXEL_TRANSPARENT)) { System.err.println ("per-pixel transparency isn't supported"); return; }
I've created a PPTSWDemo application that demonstrates per-pixel transparency and shaped windows by shaping Listing 2's rectangular gradient (without the gradient alpha values) into an ellipse. Listing 3 presents this application's source code.
Listing 3PPTSWDemo.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); } }
Sometime after verifying per-pixel transparency support, Listing 3 executes setShape (new Ellipse2D.Float (0, 0, getWidth (), getHeight ())); to shape the frame window into an ellipse. The resulting rounded window appears in Figure 3.
Figure 3 The gradient is now constrained to appear within the ellipse's interior.
Unfortunately, the shaped window has jagged edges. Perhaps the final release of JDK 7 will solve this problem by using per-pixel translucency and antialiasing. Or maybe it's possible to employ the idea presented in Chris Campbell's Java 2D Trickery: Soft Clipping blog post.