Skip to main content

JXLayer 3.0 - LockableUI

Posted by alexfromsun on July 13, 2008 at 6:47 AM PDT

LockableUI is definitely one of the most challenging feature in the JXLayer library. I have already written about why it was difficult and suggested several solutions and discuss the potential problems.
So it was a long way to make it right and now I am satisfied with the result.

In this entry I compiled all up-to-date information about this feature, so forget about the blocking glassPanes, input verifiers, old JXLayer API and let's start.

Overview

The fact that disabling a Swing container doesn't mean disabling its child components, has always been surprising for Swing beginners
(see this thread
and this one), it surprises me as well, by the way.

Consider the following code:

JPanel panel = new JPanel(); 
panel.add(new JButton("Hello"));      
frame.add(panel);
        
panel.setEnabled(false);

Despite the fact that the panel is disabled, its child button remains perfectly accessible. Actually, Swing doesn't provide a way to "disable" a container with all its child components. Recursive disabling or glassPane tricks have serious restrictions and that was the reason why I started to work on a LockableUI, which provides an elegant and safe way to temporary block a specific Swing container.

Check it out with the webstart link to the LockableDemo from the jxlayer demo package:

src="http://java.sun.com/products/jfc/tsc/sightings/images/webstart.small.jpg">

How to use it

As with all core LayerUI's, LockableUI is very easy to use:

// the component to be locked
JPanel panel = getMyPanel();
       
LockableUI lockableUI = new LockableUI();       
// wrap the panel with JXLayer and the lockableUI
JXLayer l = new JXLayer(panel, lockableUI);       
// lock the layer
lockableUI.setLocked(true);

// add the layer as any other component
frame.add(l);

After that, your panel and all its children won't receive focus , mouse or keyboard events and when you move the mouse over it, you'll see the wait mouse cursor(on Windows it is hourglass cursor), and after the

// unlock the layer        
lockableUI.setLocked(false);

the panel and all its children will work as usual. This is particularly useful when you read a big chunk of data from the network or database for a particular component - you lock it untill the data transfer has completed, leaving the rest of the GUI alive.

This is pretty cool, but to make it better we should use some visual effect for the locked layer, to notify the user that the component is locked. In my jxlayer demos I usually take advantage of standard BufferedImageOp mechanism from the core Java2D library.

With the BufferedImageOps you can have various effects like blurring, color conversion etc... For example, the following code snippet makes the locked layer black-and-white:

LockableUI ui = new LockableUI();
JXLayer l = new JXLayer(new JButton("Hello"), ui);

// Java2D grayScale BufferedImageOp
ColorConvertOp grayScale =
        new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null);
// wrap it with the jxlayer's BufferedImageOpEffect
BufferedImageOpEffect effect = new BufferedImageOpEffect(grayScale);
// set it as the locked effect       
ui.setLockedEffects(effect);
       
ui.setLocked(true);
frame.add(l);

LockableDemo

In the LockableDemo I use the beautiful set of image
effects
from Jerry Huxtable, here is his BlurFilter and plain LockableUI in action:

demo screenshot

You can also customize the LockableUI and put the unlock button directly to the layer's glassPane, see the EnhancedLockableUI implementation from the LockableDemo,
also note the EmbossFilter from Jerry:

demo screenshot

The last LockableUI's subclass shows how JXLayer and SwingX painters work together. The BusyPainterUI from the LockableDemo
uses BusyPainter from SwingX librarary and animates it to provide a nice busy effect for the locked layer:

demo screenshot

Implementation

As all other core LayerUI's, the LockableUI
neither use frame's glassPane or layeredPane, nor any other global settings like custom RepaintManager or EventQueue, it doesn't use JComponenent.print() methods, which was a problem for the old versions of this feature. All input events, including the keyboard actions, are effectively blocked for the layer's children when it is locked.

All information about the JXLayer library you can find on jxlayer.dev.java.net

See you on the JXLayer forum



Thanks

alexp

Related Topics >>

Comments

Hello Chiss Thanks for your comment, by the way you can always ask a question about JXLayer on the forum http://forums.java.net/jive/forum.jspa?forumID=140 Thanks alexp

Sorry for commenting on an old post, but I have a tip for other readers interested in the BusyPainterUI (subclass of LockableUI). I wanted to combine the Busy effect with a blurred background (basically using 'setLockedEffects(new BufferedImageOpEffect(new BlurFilter()));' but I ended up having my busy effect blurred too, which was not quite what I was looking for. After a few poking around and many ugly hacks that didn't work, I found that the simplest way to do it was to override 'paint(Graphics g, JComponent c)' INSTEAD OF paintLayer(Graphics2D g2, JXLayer l) to insert the busy effect triggering. Hope this helps! Chiss

Your library rocks! It should be rolled into base JDK if you ask me.

With LockableUI class, you add an intermediate layer between containers and components. Could it be possible to subclass containers or components instead? So my JContainers still includes sets of JComponents, whether I use the LockableUI feature or not?

Hello Jacek Thanks for your support Hello Iamlolive I don't quite get your question, LockableUI is designed to be used with JXLayer only, and JXLayer is just a component wrapper, much like JScrollPane it certainly works with JComponents Hello Mac_systems It's a tough question, first this feature was never be a high priority one and second it would be difficult to fix it in JDK in backward compatible manner Thanks alexp

Very nice. I like it very well. But i never understood why it will not be fixed in the JDK ?