Displaying validation error, and beyond, and far beyond


I was reading Kirill Grouchnikov blog  while getting a customer request to implement such a feature. Kirill wrote a series of blogs on how to support validation overlay. He did a great job in explaining different solutions and comparing pros and cons. However he doesn’t seem bother to reach a conclusion. Maybe there isn’t one after all.

No conclusion is certainly not an option for us as this particular customer is depending on a solution.

We have the following criteria in mind for this feature.

1. API ease of use - least code change to add an overlay component
2. API easy to understand
3. The overlay component is a real component, not just a painted image so that user can add mouse listener to it or set tooltip etc.
4. Can be placed beyond the component boundary
5. Handle scroll pane well
6. Support any LookAndFeels without extra code.
7. Can add overlay component to any component
8. Can use any component as the overlay component

We knew many different ways to implement this feature - most of them are pointed out already by Kirill. However, after we looked at the criteria above, we ruled out most of them. JLayeredPane/GlassPane is ruled out because of bullet 5. Overriding paint method approach is ruled out because of bullet 3 and 4. Extending or multiplex L&F approach is ruled out because of bullet 6 and 7. Let’s see what we can come up with.

First, let’s see a few screenshots.

Overlayable with different Swing components.
overlayable.png

Overlayable with JTextArea to provude a hint
overlayable_hint.png

Overlayable for progress indicator purpose
overlayable_progress.png

Overlayble with tooltips
overlayout_tooltip.png

We introduced an Overlayable interface. What overlay means is to put a component over another component. Instead of making every component overlayable, which will change too many classes, we decide to create a default implement that makes a JPanel overlayable. For example, you want to add an overlay component to a check box. You can simply add the check box to this overlayable panel, and then add overlay components to this overlayable panel. It looks like the overlay component is on the check box although it is actually on the check box parent.

Here is an example of an overlay component on a radio button.

Overlay RadioButton

The top one shows what it looks like. The icon seems like part of the radio button but it is not. As you can see from the bottom screenshot, the green rectangle is the boundary of the radio button. The red rectangle (plus the green rectangle as the green paints over the red) is the boundary of the overlayable panel. The icon is on the bottom right corner of the overlayable panel, not the radio button.

Now let’s compare the code before and after adding the overlayable.

Before adding the overlay component, we have code like the below. The controlPanel is the panel that contains the radio button.

controlPanel.add(new JRadioButton(”Radio Button”));

If you want to add an icon as overlay component, we need to create a label first.

JLabel info = new JLabel(OverlayableUtils.getPredefinedOverlayIcon(OverlayableIconsFactory.INFO));

Then we need to wrap the radio button to a DefaultOverlayable. We also need to override a method in radio button to repaint the overlay component correctly. The code will be like below. It is a little too complex.

controlPanel.add(new DefaultOverlayable(new JRadioButton(”Radio Button”){
public void repaint(long tm, int x, int y, int width, int height) {
super.repaint(tm, x, y, width, height);
OverlayableUtils.repaintOverlayable(this);
}
}, info, DefaultOverlayable.SOUTH_EAST));

Or, if you use one of the pre-build radio button, you can save the overridden method. OverlayRadioButton is nothing but a JRadioButton that overrides the repaint method as shown above.

controlPanel.add(new DefaultOverlayable(new OverlayRadioButton(”Radio Button”), info, DefaultOverlayable.SOUTH_EAST));

The code is still more complex than the original code. But considering the powerful feature it added, it is worth the added complexity.

We can easily support multiple overlay components. DefaultOverlayable’s constructor can take one overlay component. But you can still add more by calling addOverlayComponent(). For each overlay component, you can control the position, the order relative to other overlay components and visibility independently. removeOverlayComponent() will remove it and getOverlayComponents() will tell you all the overlay components.

We also support overlay component beyond the boundary. Overlayable also has setOverlayLocationInsets(). We noticed many other implementation has the limitation that the overlay component must be within the boundary of the component itself. This is annoying as the overlay component might cover portion of the component. That is why we added this overlayLocationInsets concept. If you want to place the overlay component outside the east border, you just give a positive number on the east edge of the insets. See below for an example. The first one has 0 on the east edge; 5 for the second one and 10 for the last one.

overlay_radiobutton_insets.png

Good or bad? You decide. The source code of all related classes are checked in to JIDE Common Layer at https://jide-oss.dev.java.net. In my opinion, although this design satisfies almost all the criteria I mentioned earlier, it is still not perfect especially we still have to override repaint method. One way to solve it is to provide our own RepaintManager but it will probably make API harder to understand for most developers. If Swing provided a hook into RepaintManager, it would be perfect. So in conclusion, if we would give a rating to this design from 1 to 5 with 5 is the best, I will give 5 for bullet 3 to bullet 8 and give 3 to bullet 1 and 2. There is still room to improve in these two bullets.

 For JIDE Customers, this feature will be part of 2.1.3 version which will be released tomorrow.

Information and Links

Join the fray by commenting, tracking what others have to say, or linking to it from your blog.


Other Posts
Where will you use JIDE Dashboard?
JIDE Common Layer Open Sourced

Write a Comment

Take a moment to comment and tell us what you think. Some basic HTML is allowed for formatting.

Reader Comments

David,
To reach a conclusion you need to start with a set of requirements. The validation overlay example that was used in that series was chosen to illustrate the different general techniques. Like you’re saying here, there is no “best general” solution, there is only “best for my needs” solution.
Thanks
Kirill

Totally agree. We are just trying to find a solution that is “good enough” for most general usages. Please run http://www.jidesoft.com/products/1.4/jide_demo.jnlp and open “Overlayable Demo” to see it in action. The source code of the demo can be viewed by clicking on the “Browse Source Code” button. Please let me know what you think (UI and API) as you are already the expert on this topic ;-)

These are great news! I’ll be sure to add support for overlays in JideBuilder. By the way, thanks for making JCL open source =)

Won’t it be easier to do the same thing using JComponent ZOrdering ?

Hi Pavan,

Can you elaborate? I think overlayable provides more than just Z-ordering.

I tried using Z-ordering to get rid of the overridden repaint method but it doesn’t work as I’d expect. If I don’t override repaint method and use setComponentZOrder, the icon is still overwritten when the radio button repaints (i.e when roll over under Windows XP L&F). Not sure if I used it incorrectly.

Hey David,

This seems like a pretty good solution to the problem. There is still one wrinkle though. If you have a OverlayTextField with an overlay icon on the south west corner, hanging over by say 5 pixels on each side and are trying to align that text field with another non-validatable component, there will be alignment issues - namely, it will difficult to line up the edges of the ‘main’ components.

There may be a hybrid solution - a mix of the JLayeredPane concept (http://www.pushing-pixels.org/?p=99) combined with your work discussed here. You could extend JPanel (say OverlayableJPanel) which would have all the functionality of JPanel but would also allow the installation of overlay components on other components. This be a decent compromise to the pros and cons of each individual solution.

-Ken

Ken,

You proabably need to consider the overall layout. In most cases, you don’t add extra pixels to top and bottom for small components like text field and radio button.

There is a also a trick I tried so that Overlayable doesn’t increase the perferred size of the actual component to “cheat” the parent layout manager. I tried it but didn’t get a good result.

The main problem with JLayerPane approach is it doesn’t work well if the components are inside a scroll pane. That’s why we didn’t take that approach.