Translucent shaped Windows (Extreme GUI Makeover)

When we showed off the REALiTY demo for Extreme GUI Makeover 2007 at JavaOne, I demonstrated translucent shaped windows in Java. The code behind this effect is a lot like other effects from the same demo.

In REALiTY, translucent shaped windows are used to show more details about the selected table row. You can see how it looks like in the following screenshot or in one of theses two videos: QuickTime high quality and QuickTime low quality.

Alpha Window

I really encourage you to look at the videos to see how the shaped window is animated. When shown and disposed, a fade animation is displayed. Whenever the selection changes in the table, the window smoothly follows the selection. Also, the details window sticks to the main frame when the user moves it around.

First of all, the window’s background is drawn with a simple PNG image. I could have implemented it in Java 2D, with the same tricks used for the blurry dialog, but I was running out of time. Window’s translucency is achieved with the help of JNA. I previously described how to use JNA on this blog so I won’t waste your time here.

Everything else is implemented using the Beans Binding framework and the Timing Framework. Those two libraries made the code a breeze to write. For instance, the following snippet shows how to make the window fade:

public void hideWindow() {
    Animator animator = PropertySetter.createAnimator(
            400, this, "alternateAlpha", 0.0f);
    animator.setAcceleration(0.2f);
    animator.setDeceleration(0.3f);
    animator.addTarget(new TimingTargetAdapter() {
        @Override
        public void end() {
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    setVisible(false);
                }
            });
        }
    });
    animator.start();
}

public float getAlternateAlpha() {
    return alternateAlpha;
}

public void setAlternateAlpha(float alternateAlpha) {
    this.alternateAlpha = alternateAlpha;
    AlphaWindow.updateAlphaForWindow(this, alternateAlpha);
}

As you can see, we simply set up an animator and let the Timing Framework and JNA do their job. To make the window follow the selection is equally easy. In the following snippet, AlternateDetailPanel refers to the panel that contains the pictures shown in the translucent window. We simply bind the selectionBound property of the table to the animatedLocation location of the window.

void setAlternateDetailView(AlternateDetailPanel detailView) {
    BindingContext ctx = new BindingContext();

    Binding binding = new Binding(this, "${selectionBounds}",
         SwingUtilities.getWindowAncestor(detailView), "animatedLocation");
    binding.setConverter(BOUNDS_CONVERTER);
    ctx.addBinding(binding);

    ctx.addBinding(this, "${selectedHome.photoList}", detailView, "photoList");
    ctx.bind();
 }

The selectionBound is a custom property that defines the boundaries of the selected row in screen coordinates. Here are the getter and setter for that property:

public Rectangle getSelectionBounds() {
    return selectionBounds;
}

private void setSelectionBounds(int row) {
    Rectangle oldBounds = selectionBounds;
    selectionBounds = table.getCellRect(row, 0, true);
    Point screen = table.getLocationOnScreen();
    selectionBounds.x += screen.x;
    selectionBounds.y += screen.y;
    selectionBounds.width = table.getWidth();

    firePropertyChange("selectionBounds", oldBounds, selectionBounds);
}

The setSelectionBound() method is called internally every time the selection changes. This in turn triggers the bean binding setup earlier and invokes setAnimatedLocation() on the window. Once again, the Timing Framework does all of the work for us:

public Point getAnimatedLocation() {
    return getLocation();
}

public void setAnimatedLocation(Point p) {
    Animator animator = PropertySetter.createAnimator(
            200, this, "location", p);
    animator.setAcceleration(0.1f);
    animator.setDeceleration(0.1f);
    animator.start();
}

You might have noticed that the selectionBound is a Rectangle whereas the animatedLocation is a Point. How do we convert from one to the other? This is the purpose of the line binding.setConverter(BOUNDS_CONVERTER) used when setting up the binding. This converter takes a rectangle and turns it into a point. The point is defined as being vertically centered in the rectangle and shifted to the left of the right edge:

public static final BindingConverter BOUNDS_CONVERTER =
    new BindingConverter() {
        @Override
        public Object sourceToTarget(Object value) {
            Rectangle bounds = (Rectangle) value;
            return new Point(bounds.x + bounds.width - 35,
                    bounds.y + bounds.height / 2);
        }

        @Override
        public Object targetToSource(Object value) {
            return null;
        }
    };

Last but not least we need to make the shaped window follow the main frame when it moves. Doing so is quite easy but requires two code paths, one for Windows, one for Mac OS X. On Windows, when you drag a frame, the componentMoved event is called a regular interval. However, on Mac OS X, this event is triggered only when you release the frame after the drag. That’s why on Windows we simply update the location of the shaped window when the main frame moves, whereas on Mac OS X we animated the shaped window to its new location:

theReality.getMainFrame().addComponentListener(new ComponentAdapter() {
    @Override
    public void componentMoved(ComponentEvent e) {
        Point location = reality.getMainFrame().getLocation();
        int dx = location.x - lastKnownLocation.x;
        int dy = location.y - lastKnownLocation.y;

        Point p = getLocation();
        p.x += dx;
        p.y += dy;

        if (OperatingSystemSupport.isWindows()) {
            setLocation(p);
        } else {
            setAnimatedLocation(p);
        }
    }
});

Even though this effect is not the most impressive visually, I find it very interesting because of the way it relies on the Beans Binding framework. This framework is meant to bind data between components&emdash;don’t forget that visual properties like dimensions and locations are also data!

Do not hesitate to read the session slides for further information.

21 Responses to “Translucent shaped Windows (Extreme GUI Makeover)”

  1. Joshefin says:

    How did you make cell content span in table ?

  2. Romain Guy says:

    It’s explained in the slides. It’s just some trickery with clips.

  3. Joshefin says:

    I read the slides but i still do not understand. Hope there will soon be source code …

  4. Joshefin says:

    Problem solved. The trick is in setting the view position of the viewport of the jscrollpane that contains the text area.

  5. thearipin says:

    webstart demo please?

  6. Elie Levy says:

    Romain,

    I think the “extreme makeover” presentation was great, and the demo very impressive with lots of very useful tips.

    It would be great if the code was made public for us to see and use the tricks that you guys presented there.

    When do you think you are going to be able to release the code in java.net?

    I can see that the project is there, but the access is restricted.

    Thanks

  7. Romain Guy says:

    Sun owns the code :)

  8. Lorbrito says:

    Cant be!!!!!
    the before project it can be downloaded,, why this not?

  9. sdark not says:

    si alguien tuviera ese ejemplo me lo podrian mandar a mi correo darkx_valen666@hotmail.com desde ya gracias

  10. Gene says:

    Incredible. An “expert” on UIs with a web site that uses a nearly unreadable dark grey text #777777 on darker grey #222222 background. What are you thinking? Oh, that’s right, you’re NOT thinking.

  11. Romain Guy says:

    Gene, no need to be a dick about it :) I admit being guilty of laziness and not fixing this issue since I changed this website’s theme. The main reason is that I mostly post pictures now so I didn’t really care about the text. Anyway, since it’s bothering my readers, you can now choose between a white theme and a dark theme (with lighter text than when you wrote your nice complaint.) Enjoy.

  12. Gene don`t be so hard with Romain besides if you think that it`s inappropiate the theme YOU SHOULD MAKE IT BY YOURSELF, b…..h

  13. Romain is in fact a true expert O.K

  14. riszkhy says:

    Thanks for the articel…..

    Now, i get inspiration to make the my application…

    one more again….

    i’m very-very thanks…

  15. Keri Irvin says:

    Why in the world would I try to learn this the hard way? I have a tons of CD tutorials I got for free lol…. —–> check it: http://bit.ly/learning-software

  16. Wow. I can’t understand how France lost. That was a fast exit. I really assumed that they had a great opportunity to do well in this years world cup. I guess I will have to wait. Maybe its time to jump on the Argentina bandwagon. Looks like Demichelis has already scored. Go Argentina. To make me feel a little better from that by France, I have been watching some funny jokes.. This was super hillarious: http://www.youtube.com/watch?v=N3j7uSbccSc

  17. Jorge Laning says:

    I can’t believe LeBron is going to the Bulls, he should really just stay where he is.

  18. I’m really to be finally posting online after all these years. There really is no mystery about it, is there? I just dropped by your blog and had to write. I’m a recent college grad, journalism major if you must know, and I absolutely love the art of photography. I’ve got my website up but it’s nothing to brag about yet. None of my stuff’s been posted. Soon as I figure out how to do that, I’ll spend the day posting my best pictures. anyways just thought I’d drop a line. I hope to return with more substantial stuff, stuff you can actually use. SPG