Home > Articles > Programming > Java

  • Print
  • + Share This
Like this article? We recommend

Like this article? We recommend

Per-Pixel Transparency and Shaped Windows

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 3—PPTSWDemo.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.

  • + Share This
  • 🔖 Save To Your Account