While the last two entries on AOP and JXLayer tried to address the immediate shortcomings of the paint() method (need for custom repaint manager and not using “pure” components), there is yet another limitation that was pointed out in the comments – what if you want to paint the validation overlay outside the component bounds? Here is a screenshot to illustrate this:

Validation overlay, glass pane with offsets

Note how the overlay icons are painted partially outside the component bounds (in this specific case, the offsets are two pixels in both dimensions), which provides a much “cleaner” view of the underlying component without sacrificing the validation icon size or opacity. So what is the limitation that we are talking about? The main reason why this is difficult to achieve with the techniques that we have seen (borders, paint() and JXLayer) is that they all are restricted to paint inside the component bounds (for more details see the JComponent.paintWithOffscreenBuffer method).

Can this be addressed? It most certainly can with techniques that operate on the “frame” level. For example, this limitation is not relevant for repaint manager since it can paint anywhere on the frame (with all the other limitations mentioned in that entry). Another frame-level technique that is available in Swing is glass pane. As i mentioned in my presentation, glass pane is a very simple and powerful technique that should be known by every Swing programmer. In one sentence, think about it as a layer that is painted over the entire frame. This means that you can paint whatever you want without being restricted by the component hierarchy or the component bounds. However, with this great power come two big disadvantages (mentioned in the introduction section of the entry on JXLayer).

The first is that when your glass pane is not opaque (as it would be in most cases since you would want to show at least some part of your application behind the glass pane), Swing has to repaint the entire frame before painting the glass pane. If you have a big frame, a lot of controls or a lot of custom painting logic, this can be very CPU-heavy process. In some cases, you might address this by taking the snapshot of your application, declaring your glass pane as opaque and just painting the application snapshot before painting the actual contents of the glass pane, but this would only work if the contents of your frame do not change as long as the glass pane is visible.

The second disadvantage of glass panes is that you can only have one glass pane installed at any given time on the specific root pane (which roughly corresponds to a window). So, if you want to use one glass pane for validation overlays (like i’ll show shortly) and another glass pane for infinite progress indication while your UI goes to the server, you’ll have to combine both painting sequences in one panel. Furthermore, you can have “rogue” third-party libraries that will install their own glass panes as the internal implementation details.

While these two issues are successfully addressed by the JXLayer implementation, it has its own shortcomings as mentioned in the relevant entry and above – you need to wrap each component with JXLayer (“tainting” you UI code) and JXLayer can only paint inside the component bounds. Note that the second limitation can be addressed in a more complicated way by wrapping the entire content pane with one big JXLayer that will paint all the validation overlays. The next entry on layered panes will show a more elegant approach to solving this problem.

The classes in this entry are located in the org.pushingpixels.validation.glasspane package implement the validation overlays using a custom glass pane. The GlassPaneSampleUi extends the basic SampleUi, adding a custom glass pane to the frame and making it visible. The glass pane itself is implemented in the ValidationGlassPane class. The constructor defines the panel as non-opaque (since we want all the components be visible “behind” the glass pane), and the paintComponent() method implements our visitor interface to paint the validation icon on relevant components with negative offsets.

There are two important points in this implementation. The first is that you need to compute the offsets between the root pane (the start of the visitor pattern implementation) and the glass pane itself (this is especially important since the implementation must run correctly under both decorated and undecorated mode). The second is the implementation itself of the visitor in the org.pushingpixels.validation.Visitor.visit method. It only paints components that intersect the current clip set by the most recent repaint event. This allows us to paint validation overlays only on the “dirty” portion of the UI. Note how in org.pushingpixels.validation.SampleUi we register a document listener on the text fields that repaints the entire frame on a document change (because in our case we want the validation overlay to be painted partially outside the text field bounds, but we don’t want to put the exact offsets in the document listener; of course this will cause the entire frame to be repainted before the glass pane is repainted, so this might be a big performance hit). Then, in the Visitor.visit we compute the intersection between the current clip and the extended component bounds. If there is intersection, we paint the validation overlay.

When you run the GlassPaneSample class, play with the first text field. When the contents are empty, the validation icon will not be painted:

Validation overlay, glass pane with offsets and no icon on one textfield

In conclusion, you can see that a glass pane is a viable alternative to implement the validation overlays, especially when the the icons need to be painted partially outside the component bounds. While with proper coding of intersections with clipping area you can address the performance issue of the glass pane itself, the issue of repainting the entire underlying frame remains. In addition, we’re still using the global glass pane resource. The next entry on layered panes will address the later issue.

To continue addressing the disadvantages of overriding paint() for showing validation overlays, this time i will talk about the JXLayer component. Developed and maintained by Alexander Potochkin, it is one of the most versatile Swing utilities that i have seen in the last two years. One of the next entries will talk about using a glass pane for validation overlays; it will also mention the two main disadvantages of glass panes

  • You can have only one glass pane for a top-level window (flexibility)
  • When glass pane is repainted, the entire frame is repainted with it (performance)

The best way to describe JXLayer in one sentence would be that it provides the functionality of a glass pane on the component level. While addressing both disadvantages of glass panes, it also has advanced APIs to set custom alpha value, install filters and support non-rectangular components. What does this have to do with validation overlays?

Using JXLayer allows us to address one limitation of directly overriding paint() – we don’t need to install a custom repaint manager to extend the dirty region from an inner component to its containing complex component (say, from the inner text field to the containing editable combobox). Note that the second limitation (not using “pure” core components) unfortunately remains.

All classes in this entry are located in the org.pushingpixels.validation.jxlayer package. The JXLayerComponentFactory provides a custom painter for JXLayer that paints the component itself and the validation icon if necessary. In addition, it provides a utility method to “wrap” any JComponent with our custom JXLayer. The JXLayerSampleUi creates the UI itself – note that instead of adding “regular” components (such as JTextField or JComboBox), it wraps them with JXLayers and adds those (much as you would add a JTable wrapped in a JScrollPane, so the notion is not completely foreign to a Swing developer).

The biggest gain from using JXLayer in our example is that there is no longer need for a custom repaint manager. Since it wraps our component with an additional “glass sheet”, Swing knows that it needs to repaint the entire component when any of its parts is dirty. Since we’re operating on a single component (and not on the entire frame as glass pane does), the performance penalty is more than acceptable (remember that repaint manager is a global resource, so not having to install one is a very good thing). Here is how our UI looks like under JXLayer:

Validation overlay, JXLayer

As i mentioned in the previous entry, one of the disadvantages of overriding the paint() method for validation overlays is that you need to do it for each one of the components that can have validation errors. So, you no longer use a “pure” JTextField, for example. You either override the paint() method when you create your text field, or use a custom class that extends JTextField and overrides the paint() method. Needless to say that the impact on your UI creation code is rather large and unpleasant. Wouldn’t it be nice if you could just inject the required functionality to all Swing components?

Although i might not be the biggest fan of aspect-oriented programming (AOP), it certainly sounds like a promising approach. In fact, AOP has been shown to address other Swing-related problems by Ben Galbraith (for adding property change support on Java beans) and by Alexander Potochkin (for tracing EDT violations). Disregarding all the hype around AOP (that seems to have thankfully died over the past year), the eventual result is that you inject the functionality you need at the specific methods in your classes. In fact, i used a very similar approach in one of my look-and-feel related projects. Isn’t this exactly what we’re looking for?

Well, it almost is. The main caveat with the bytecode injection (which is the eventual result of applying aspects to the classes) is that it is done on the bytecode class that you can control. The examples mentioned above apply this technique on the application classes. Where do we want to apply this? Mostly (unless you override the paint() method) on the core JVM classes. And this is where our problem lies.

AspectJ is one of the leading implementations of AOP in Java (especially since it has joined forces with AspectWerkz some time ago). Its load-time weaving (LTW) explicitly excludes the core classes (that would be JComponent among the rest). In addition, your application most probably doesn’t call the paint() method itself (that is left to the Swing painting pipeline, and as we have seen in the discussion on the repaint managers, there is no extension point that paints a specific dirty component). And so, if you want to use AspectJ, the only other possible option is to weave the core classes at compilation time.

You can download and build Swing using the latest JDK 7.0 weekly builds. Then, you can weave your aspect into the created swing.jar and put it in front of the bootstrap classpath. While certainly doable, this approach is far from optimal. First, you bundle an extra 4.1MB jar. Second, you’re confining yourself to the specific JDK build, including all its bugs. Third, you might run into classloader problems in specialized runtime environments, such as WebStart, applets and others.

A way around the limitation of weaving core classes would be to extend all the core Swing components, override the paint() method to call the super implementation and the weave the validation overlay logic. While it will work, it is hardly an improvement over overriding the paint() directly (without the overhead hassle of using aspects); you’ll still end up not using the core components directly in your code.

While the list of Java AOP frameworks contains other options (besides AspectJ), i am not aware of another AOP-based approach that will allow weaving core classes at runtime without any limitations. If you know of any, i will be more than happy to hear about them in the comments.

In the previous entries on painting validation overlays using repaint manager and borders i discussed why it it important to find the best painting pipeline hook that matches the specific requirements. The repaint manager is an “overshoot” since it allows painting only after all the dirty components have been painted. The borders are “undershoot” since they are painted before the child components are painted. In this entry i’m going to discuss the <a href="http://java.sun.com/j2se/1.5.0/docs/api/java/awt/Component.html#paint(java.awt.Graphics)">paint()</a> method which is one of the best hooks fit for our requirements.

While it is not recommended to override the paint() method (specifically because if you don’t call the super implementation, you “lose” the border and the children), doing it correctly is a very useful tool in any Swing developer’s arsenal. In our case, we want to paint an overlay icon on top of the component (which might have child components in it). Well, as long as the overlay icon is painted inside the component bounds, we can override the paint() method, call the super implementation (that will paint the component, its border and its children) and then paint our icon. There should be no special cases except one – extending the dirty region with a custom repaint manager (more on that later).

Let’s try implementing the validation overlays with custom paint() implementation. Note that all classes in this entry are located in the org.pushingpixels.validation.custompaint package.

The major disadvantage of overriding the paint() method is that you have to do it for every component that can display validation errors. Of course, you can come up with a factory that returns a preconfigured instance of such a component (sample implementation in the CustomPaintComponentFactory class), but it still “pollutes” your UI code with the calls to that factory. In addition, this might prove problematic with visual editors such as Matisse. Furthermore, you will have to provide a factory method for each component class (for those components that can have validation errors) and repeat the same painting code in each one of these.

The end result, however, is exactly what we’re looking for – the validation errors that are displayed on top of the components (including editable combobox that has an inner textfield implementation child):

Validation overlay, paint()

The only thing that must be mentioned (and was already mentioned in the previous entries) is the case of complex components. Here is how our UI looks like when we click the editable combobox (without a custom repaint manager installed):

Validation overlay, paint() without repaint manager

Swing is smart enough to repaint only the editor (and hence paint the validation icon in the editor bounds), but not smart enough to figure out that this editor is an integral part of a “larger” component (which means that the validation icon is not be painted outside the editor bounds, resulting in a clipped indication). Without a custom repaint manager (with its “globalness” shortcoming addressed in the relevant entry) you can end up with temporary visual artifacts (until some event that triggers the repaint of the combobox itself).

There are two possible solutions. The first is to install a custom repaint manager that extends the dirty region from the inner text field to the combobox itself. The second is to trigger the repaint of the combobox from the inner text field. The later is much more complicated, since you will have to override the paint() method of the inner text field and guard against an infinite repaint loop (repaint of combo triggering repaint of text field that trigger the repaint of combo in turn). While this can be done, it is not trivial.

As we have seen, while the custom paint() implementation is a good fit for painting the validation overlays, it a has a few disadvantages:

  • Need to override paint() for each component class that can have validation errors
  • Need to install a custom repaint manager to trigger repaints of complex components

In the following entries, i will discuss a few alternatives that try to address these issues.