The Source for Java Technology Collaboration
User: Password:



Joshua Marinacci

Joshua Marinacci's Blog

Java Doodle: fading translucent windows, on PC & Mac

Posted by joshy on June 06, 2008 at 03:05 PM | Comments (9)

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


Bookmark blog post: del.icio.us del.icio.us Digg Digg DZone DZone Furl Furl Reddit Reddit
Comments
Comments are listed in date ascending order (oldest first) | Post Comment

  • I notice this screenshot is on OSX. Can you comment yet on the availability of 6u10 on Mac yet? Now or after next week?

    Posted by: shemnon on June 06, 2008 at 05:34 PM

  • I mean, you can't keep using these if platform workarounds on WORA stuff forever, c an you?

    Posted by: shemnon on June 06, 2008 at 05:36 PM

  • I have no news on 6u10 for Mac. However, as this blog shows, you can do some of the u10 features on Mac already.

    Posted by: joshy on June 06, 2008 at 05:49 PM

  • If its a com.sun class doesn't that mean it most probably wont be implemented on other OS's?

    It's a fun Doodle; What about custom shaped windows?

    Posted by: ant001 on June 07, 2008 at 04:04 AM

  • Great blog Josh...good stuff as always! Java 6u10 is looking great!

    Posted by: juneau001 on June 07, 2008 at 08:06 AM

  • I'm curious to know why Sun didn't fix JComponent.setBackground(Color c) where Color has an alpha parameter. That would seem to be an obvious solution.

    It is a nice example though.

    Posted by: mediarazzo on June 09, 2008 at 08:59 AM

  • mediarazzo changing the definition of setBackground() would effectively be changing the API, which is not allowed in an update release. However, that method or something like it may end up being the final API which is included in JavaSE 7.

    Posted by: joshy on June 09, 2008 at 09:05 AM

  • Polling the global mouse position? ... Polling? Seriously, there has to be a better way. Why isn't there a global mouse position event listener?

    Posted by: cowwoc on June 09, 2008 at 07:23 PM

  • Josh, fixing a bug isn't changing an API. And if the method responds incorrectly to colours with transparancy that's a bug that needs to be fixed. Of course the behaviour of the API will change, but that's the nature of bugfixes, to change the behaviour of APIs or applications so they work as specified...

    Posted by: jwenting on June 09, 2008 at 11:55 PM



Only logged in users may post comments. Login Here.


Powered by
Movable Type 3.01D
 Feed java.net RSS Feeds