Hacking Swing: Translucent Windows

Editor's note: The following example from Swing Hacks is one of the book's most visually daring hacks--mimicking the arbitrarily shaped window you might see in an native MP3 player skin. The hack here is necessitated by the fact that Java doesn't support non-rectangular windows, so the only option to make this work is for the Java window to be aware of what's under it, and to handle the imaging of areas within the window's rectangle but not within its arbitrary shape. Read on for how this is accomplished.

Create translucent and shaped windows, while avoiding native code, with clever use of a screenshot.

One of the most commonly requested Swing features is transparent windows. Also called shaped windows, these are windows that have transparent portions, allowing the desktop background and other programs to shine through. Java doesn't provide any way of creating transparent windows without using the Java Native Interface (JNI) (and even then the native platform must support transparency as well), but that's not going to stop us. We can cheat using one of my favorite techniques, the screenshot.

The process of faking a transparent window is basically:

Take a screenshot before the window is shown.

Use that screenshot as the background of the window.

Adjust the position so that the screenshot and the real screen line up, creating the illusion of transparency.

This is the easy part. The hard part is updating the screenshot when the window moves or changes.

To start off, create a JPanel subclass that can capture the screen and paint it as the background, as shown in Example 6-1.

First, the constructor saves a reference to the parent JFrame; then it calls updateBackground( ), which captures the entire screen using java.awt.Robot. createScreenCapture( ), and saves the capture in the background variable. paintComponent( ) gets the panel's absolute position on screen and then fills the panel with the background image, shifted to account for the panel's location. This makes the fake background image line up with the real background, giving the appearance of transparency.

You can run this with a simple main( ) method, dropping a few components onto the panel and putting it into a frame: