Archive for February, 2005

This week has been very busy on this blog so here is a little summary of what’s going on:

  1. – Jan Böesenberg tried something nice with the InfiniteProgressPanel (see below)
  2. Craig, author of the recent JDraggable project, and I will be working on a set of Swing components likely to be called SwingFX. Stay tuned.
  3. – I’ve improved AnimatedPanel.java and InfiniteProgressPanel.java. They’re now full of comments, under the BSD license and more customizable. I might create another InfiniteProgressPanel based on Jan’s experiment (see below).
  4. – Chet Haase and some others in the comments gave me ideas to improve the performances of the spotlights demo when the blur is turned on. Remember, you can already animate spots by turning blur off. I have some really ideas in mind :)
  5. – I already have a few other ideas of Swing demos but I’ll have to wait till the 28st of February to play with them. As much as I like Swing, I still prefer ski :)

Here is what Jan did with the infinite progress demo, I find it really cool:

See you in a week and thanks.

* with style followup

You can run the WebStart demo or, as usual, download its source code. The code you want to look at is in SpotlightPanel and Spotlight classes.

Most of applications involve data manipulations. You create, edit, delete, move and… search for data items. A lot of common UI controls allow to display search results in a practical way but they all lack a bit of fancy. Apple's next version of MacOS X, Tiger, will introduce a cool new search technology called Spotlight. In the preferences dialog you can type in a query and see cool spots shedding light on the icons which lead to the function you were looking for. Should we wait a few months to give it a try? Or should we use Swing to use the same trick now?

While cool, this visual effect can only be applied to small sets of data. In today's demo, I've set up a fake books shelf application:

The text field at the bottom of the frame lets you enter a search query to know which books in the shelf are the ones you're looking for. In this demo, only the queries “sci-fi”, “adams”, “pratchett” and “books” will lead to some result, so don't be too original here. Enter one of this queries, press the Enter key and here is what you should see:

Pretty isn't it? In this example I have run the query for “sci-fi”. Here is the result for “pratchett”:

Did you notice how the black veil adapts its opacity according to the amount of light shed onto it? The more spots you create, the less black it appears. And don't worry, spots can overlap:

Setting up this cool effect is very easy and it is just a matter of a few lines of code. The trick uses, once again, a glass pane:

SpotlightPanel glassPane = new SpotlightPanel();
this.setGlassPane(glassPane);
// a circular spotlight
glassPane.addSpotlight(50, 50, 100);
// an ellipse
glassPane.addSpotlight(100, 100, 25, 75);

Each call to addSpotlight() returns a Spotlight instance you can use to animate the spot. The big problem with the actual code is caused by the blurring filter in the paint method. I apply a ConvolveOp on the glass pane. As the frame is pretty big, it consumes a lot of CPU power. On slow computers you'll see drawing slowdowns while you will move the mouse cursor above the window. You can work around this by invoking the constructor new SpotlightPanel(false) to disable the blur. The result is less cool but you can now animate the spotlights! If you leave the blur turned on, no animation will ever run smooth enough, believe me.

So please, could somebody find a clever way to fake the blur on each spotlight? It would even allow to change the blur amount of each spot, depending on the relevance of each search result. A sharp spot would point out a very good result whereas a blurry one would point out a partial match. I've already tried to fake the blur by drawing smaller ellipses in each spot but I did not find a good way to compute the colors. Help me :)

Search with style in Swing

You can run the WebStart demo or, as usual, download its source code.

One very cool way to create user friendly interfaces is to provide the ability to drag and drop just about anything from, within and onto the application. MacOS X is a perfect example of a good drag and drop use. Everytime I try to drag something to drop it onto something else, it works. At least given you're not trying to perform something stupid like dropping a text file onto a game icon. Anyway, Windows and Linux let the applications implement drag and drop but they lack something MacOS X already offers: really cool visual feedback. For instance, dragging a picture from Safari, the web browser, shows a nice translucent thumbnail of the object. The user always knows what he is exactly dragging.

How could we then get rid of the simplistic drag and drop cursor that Java provides us? The solution lies in the Drag n' Ghost Demo I'm about to show you. See for yourself, don't you like this nice translucent picture?

Dragging a picture is cool but what if we could drag just about any components and still get that nice effect? No problem folks:

Still not convinced, see what dragging a whole, fully loaded JTable looks like:

Now that I have your attention, let's see how to use it in your applications. The trick is to use a glass pane to paint the translucent picture of the components over the UI. Therefore, you must set the GhostGlassPane to the frame and then attach a GhostDropAdapter and a GhostMotionAdapter to the component you want to be able to drag and drop:

GhostGlassPane glassPane = new GhostGlassPane();
setGlassPane(glassPane);

JLabel label = new JLabel("Component adapted");
label.addMouseListener(new GhostComponentAdapter(glassPane, "action_1"));
label.addMouseMotionListener(new GhostMotionAdapter(glassPane));

JButton button = new JButton("Picture adapted");
label.addMouseListener(new GhostPictureAdapter(glassPane, "action_2", "image.png"));
label.addMouseMotionListener(new GhostMotionAdapter(glassPane));

And that's it, it is as simple as that. You may have noticed we do not use a GhostDropAdapter but its two subclasses, GhostComponentAdapter and GhostPictureAdapter. The first one creates the ghost picture by painting the source component in an offscreen image whereas the second one uses the ghost picture you provided.

Every GhostDropAdapter can register GhostDropListeners which are invoked when the drop occurs. The event is an instance of GhostDropEvent which gives you the action name and the location of the drop. Since the location is in screen coordinates, it is advised to use the AbstractGhostDropManager which provides two interesting methods.

Such a manager is tied to a component (see the constructor) called the target. Two methods let you handle the target component: isInTarget() checks whether the drop location is located within the bounds of the target component and getTranslatedPoint() translates the screen coordinates into target coordinates. The GhostDropManagerDemo shows how to create a custom manager. In this case, the manager waits for a drop onto the JTable and pops up the action name:

The GhostDrop components set suffers from two problems though. First, performances can be quite bad when you drag a ghost over a large window. I've seen it happen only on my computer but I have no doubt it will happen on some of yours too. I can't see how to optimize the rendering apart from using a VolatileImage (and I'm not sure of the result). The second problem happens when the focus is given to another window while you're dragging something. The ghost remains painted on the glass pane. I think this can be fixed quite easily by listening to the focus of the parent window.

Drag with style in Swing

I updated the Wait with style demo for Matt Schmidt. You can WebStart it or download its source code.

Changes:

  • You can now set a message
  • You can set the amount of bars in the shape
  • You can set the number of frames per second (default is 15)
  • You can use setFont() and setForeground() to change the text's appearance
  • Text can be changed at runtime with setText()
  • An empty or null string prevents the panel from drawing the text
  • quit() has been renamed to interrupt(), which you should call to stop the animation without starting the ending animation phase (useful when the user quits the application for instance)

Wait with style, updated

You can WebStart the demo or download its source code. Only the AnimatedPanel.java and InfiniteProgressPanel.java files can be used freely without any restriction. Contact me for the other files.

UIs can be very annoying, especially when they seem to be doing something but they don't want to tell you what. Worse, some don't even bother telling you how much time they will need to complete the current task. As a user I experienced this way too often. As a programmer I know how hard it can be to determine the duration of a task.

That is why some applications, like Mozilla's installer, use an infinite progress bar. This kind of component ususally looks like a standard regular bar but act a little bit differently. In Mozilla's case you can see a rectangle bouncing within the bar's bounds. I've also seen infinite progress bars acting like regular progress bar but going backward once filled or starting over again. Although the infinite progress bar is a good idea, these implementations suck. There is no way for the user to understand at once that the progress bar is in fact “infinite”.

Hopefully, there are easy way to work around this limitation. I've built two examples to show what kind of infinite progress components can be created with Swing. The first one simply shows glowing picture and label:

I really suggest you to run the WebStart demo to show it in action. Once the application is started, click onto View Sale and then on the Search button. The source code of this effect lies in org.progx.salesmanagers.ui.AnimatedPanel. Such a panel is made of a message and a picture. An animation thread changes the transparency of the message and the brightness of the picture back and forth. The source code is fairly easy to understand.

This first solution is nice but not as powerful as it could be. In this example, the UI remains active during the animation. A complete program should take care of disabling all the “dangerous” components. My second solution relies on the glass pane of the window. As you might know, a glass pane is a component sitting on top of all the other layers of the window, especially the content pane. By intercepting all the mouse events in the glass pane, you block all the application (key events should also be handled to prevent the use of accelerators).

I also chose another way to render an infinite progress bar. Inspired by MacOS X, org.progx.salesmanagers.ui.InfiniteProgressPanel draw a circular set of rotating bars. And guess what? A circle is just the perfect shape to show the infinite property of the progress components. Finally I added a white veil to show the UI cannot be manipulated anymore. Here is what it looks like:

You should really try the online demo for this one :) Once the application is started, click onto New Sale and then on the Perform Sale button. You'll notice the fade in and fade out of the panel. The default constructors allow you to set up the transparency of the veil and to change the duration of the fade in and fade out animations. The code uses some Java2D operations but remains easy to understand.

One remark though: the InfiniteProgressPanel was written very quickly and the code is a mess, particularily the animation thread (which should have been splitted into three threads). The sleep delays used in the animation thread tend to consume a lot of processor power on not-so-recent computers (P4 1.5 Ghz). It definitely needs some tweaking and optimization :)

Wait with style in Swing

Update: you can launch a WebStart version of the demo.

Have you ever wondered how to use nice 3D components with Swing? Java3D is the way to go. Yet, at a first glance, Java3D does not let you integrate 3D scenes smoothly in your UI. If you saw the Microsoft's Avalon demo videos you know what I'm talking about. Avalon won't be available before months (some say years) but Java and Java3D are already here.

With a simple trick you can create visual stunning Swing applications. Here is an example:

Notice the gradient background I've put here to show the unity between Swing and Java3D. Before getting into the details, let's see what this application is capable of. I called this demo AmazonPick because it would be a great UI for a book searching application. When books match your query, they are displayed as buttons at the bottom of the window (in this case, the buttons are hard coded). Whenever you click one of them, the 3D “book” flips to show a new cover on the other side. Neat effect.

    

To achieve this I simply created a Java3D texture on which I painted the frame's background. Here is the source code, xpanel being the frame's content pane and c3d being the Canvas3D in which the scene is rendered:

BufferedImage image = new BufferedImage(xpanel.getWidth(),
                                        xpanel.getHeight(),
                                        BufferedImage.TYPE_INT_RGB);
getContentPane().paint(image.getGraphics());
    
BufferedImage subImage = new BufferedImage(CANVAS3D_WIDTH,
                                           CANVAS3D_HEIGHT,
                                           BufferedImage.TYPE_INT_RGB);
((Graphics2D) subImage.getGraphics()).drawImage(image, null,
                                                -c3d.getX(), -c3d.getY());

Background bg = new Background(new ImageComponent2D(ImageComponent2D.FORMAT_RGB, subImage));

BoundingSphere bounds = new BoundingSphere();
bounds.setRadius(100.0);
bg.setApplicationBounds(bounds);
    
BranchGroup objRoot = new BranchGroup();
objRoot.addChild(bg);

Although this is easy to implement this trick requires the component used a background texture to be realized. In our case, this means we need to show the frame. The user will therefore see a gray canvas for a little while.

Using Java3D has many advantages but requires a little trick to work perfectly. A Java3D Canvas is an heavyweight component whereas Swing is made of lightweight components. The result is all the Swing components are drawn below the Java3D Canvas. The Swing and Java3D teams are aware of this problem and there is a simple solution.

As of Java3D 1.3.1 a better solution exists. You can use offscreen Canvas3D to perform offscreen rendering. This means we could do all the rendering job in a buffer and paint the resulting frames directly within a Swing component (with a customized JComponent or an ImageIcon). This, however, requires more work.

You can download the demo and its source code to see how to achieve this effect. You'll need Java3D 1.3 and J2SE 1.4 (maybe less, more is good too). If you have only J2SE 1.4, you can change one or two lines of code in BooksDemo.java to get rid of generics and recompile it safely.

Let me know if you successfully use this trick!

3D with Swing

I’ve finally added some “real” components to the WaveUI Demo. The screenshot shows three buttons, either enabled or disabled. To implement this I had to create a new UI delegate for the JButton component. This led me to write a few awful lines of code to bypass some Metal look and feel settings. I definitely need to create a real Wave look and feel. Anyway, here is the result :

I won’t talk about WaveUI in my next entries. You can download the source code and see how one can create a nice looking UI with hideous code :)

Important Note: the WaveButtonUI uses code from Karsten Lentzsch’s Plastic Look and Feel. Plastic comes with the Looks package which is distributed under BSD license.

Wave UI, Part 3

I have a lot of work to achieve on this UI to make it usable in real world applications. I tried to put my OSX-like text field in the mockup and it looks quite good. See for yourself:

The search field source code is not really efficient. If you look closely at the “edges” you can see minor glitches, due to the use of Arc2D.Double. I think I could do a better job with rounded rectangle and precise clipping regions.

The next steps will be to turn the white background into a wavy-greenish one and to create buttons for this “theme”. The background will need to be very subtle to not interfere with readability.

Wave UI, again

Well, I've finally opened my blog on jroller.com (thanks Rick :). I would like to start this new web site with an elegant mockup I've made with Swing yesterday. It uses customized JPanels, JLabels and JComponents to offer a pleasant UI which looks like a web site. I have to admit I was inspired by a blogger.com template. That's why I need to change some stuff like the stacked rounded rectangles ^^

Anyway, I have to implement a video stream client for school and I think this UI would be perfect. Subclassing components is somehow tedious but I'm not in the mood to write clean UI delegates. A better solution would be to go with Synth but school stations run J2SE 1.4. Maybe I will build a look and feel after all. It would be a cool training for my internship at Sun Microsystems this summer ;-)

Anyway, here is the first mockup of the Wave UI Demo:

If you want to know more about my recent works with Swing, check out #ProgX, my french web site.

Wave UI