Java Doodle: fading translucent windows, on PC & Mac

This is the next in my series of Java Doodles. There is a link to my previous one in the references below. This time I'm going to show you how to make a translucent window by setting the opacity value using new apis in JavaSE 6 update 10. However, I'm also going to show you how to make it fade in when you mouse over it, similar to some popular chat applications, as well as work properly on the Mac and degrade gracefully when running versions of Java.

The basic idea

Here is a screenshot of the basic app. It's a simple translucent window. I've you've read the recent SDN article then you probably already know the basic APIs. This app will add Mac support, a rollover effect, and show you how to degrade gracefully.

Translucent Window

Degrading gracefully

Turning on translucency with Java SE 6 is as simple as calling a new private API: com.sun.awt.AWTUtilities.setWindowOpacity(float). To make it degrade gracefully on older VMs we could test if the feature is supported using the isTranslucencySupported() method. However, this API will probably change in Java 7 (since it's currently in a non-public package) and of course it doesn't exist on older versions of Java. If I want to compile this on an older VM (such as on my MacBook) then I simply can't call the API directly. Instead I'll use reflection and wrap it in a try catch block. I've created my own method called setAlpha(float) which will safely call the setWindowOpacity() method.

    private static void setAlpha(float alpha) {
        try {
            Window win = frame;
            //invoke AWTUtilities.setWindowOpacity(win, 0.0f);
            Class awtutil = Class.forName("com.sun.awt.AWTUtilities");
            Method setWindowOpaque = awtutil.getMethod("setWindowOpacity", Window.class, float.class);
            setWindowOpaque.invoke(null, win, (float)alpha);
        } catch (Exception ex) {
            //ex.printStackTrace();
        }
    }

Now, if the method doesn't exist at runtime because the user has an older version of Java then the exception will be caught and nothing will happen. It degrades gracefully.

Mac support

So what about the Mac? Well, Mac OS X doesn't have a version of Java SE 6 update 10 yet, however in Leopard they did introduce a new API for doing translucency. Using this new support we can add translucency on Mac with a single extra line. In the catch block above we can add this:

        } catch (Exception ex) {
            //ex.printStackTrace();
            frame.getRootPane().putClientProperty("Window.alpha", new Float(alpha));
        }

This sets a magic property on the rootpane of the frame called Window.alpha. Because this is a client property it will have no effect on other platforms that don't know about it. Again, degrading gracefully.

The fade effect

Now that we can make a window translucent lets do something interesting with it. I want the window to be mostly transparent, but whenever the mouse moves into the window I want to return to mostly opaque. So let's say the opacity will go from 0.5 to 0.9. I could set a mouse listener on the background of th window, but that wouldn't work on subcomponents. I could also put in a glasspane to check for mouse events, but then I would have to redispatch all events back down to the real components as I did in my book Swing Hacks. Very messy. Fortunately, as of Java 5, we have an easier method: just poll the global mouse position using the MouseInfo class. Here's a Runnable which does that:

    private static Runnable mouseWatcher = new Runnable() {

        public void run() {
            boolean previouslyInside = false;
            while (true) {
                try {
                    Thread.sleep(100);
                    Point pt = MouseInfo.getPointerInfo().getLocation();
                    boolean currentlyInside = frame.getBounds().contains(pt);
                    if (previouslyInside != currentlyInside) {
                        if (currentlyInside) {
                            setAlpha(0.9f);
                        } else {
                            setAlpha(0.5f);
                        }
                    }
                    previouslyInside = currentlyInside;

                } catch (InterruptedException ex) {
                    Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
          ��     }
            }
        }
    };

The code above will check the mouse position ten times a second. If the mouse has moved in or out of the window then it changes the opacity. It's that simple.

Run the app

You can try the live application here. It will work on MacOSX 10.5 or Windows/Solaris/Linux if you have a recent beta of JavaSE 6 update 10. On older versions of Java 6 you won't get the translucency effect, but the app will still run.

That's all there is to it. This is just one of the many cool new features in JavaSE 6 update 10. Go check'em out then come back to my blog for more Java Doodles in the future.

Bookmark and Share

References

Talk to me about it on Twitter

Posted June 6th, 2008

Tagged: java.net