Validation overlays using paint()

July 30th, 2007 | 3 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 paint() 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.


Related posts:

  1. Validation overlays using borders Every core Swing component inherits the setBorder() method from the JComponent. In this entry i’m...
  2. Validation overlays extending a specific look and feel With the last few entries essentially using the same part of the Swing painting pipeline...
  3. Validation overlays using JXLayer To continue addressing the disadvantages of overriding paint() for showing validation overlays, this time i...
  4. Validation overlays using glass pane While the last two entries on AOP and JXLayer tried to address the immediate shortcomings...


3 Comments on “Validation overlays using paint()”

  1. 1 Aberrant said at 4:50 am on August 7th, 2007:

    These articles have been really great. I have a question though. What about the addDirtyRegion() method from RepaintManager? Can’t you just mark the region you are painting the icon to dirty? Is this bad performance wise? I’m pretty sure the entire parent component does not get repainted. At least in my tests it looked that way.

  2. 2 Aberrant said at 7:55 am on August 7th, 2007:

    Forget it, upon further review I seem to have an infinite loop. Of course everything paints but it does way too much work.

  3. 3 Kirill Grouchnikov said at 9:49 am on August 7th, 2007:

    Aberrant – one option is to register a document listener on the internal text field and have it track the validity of the value. Then, if the validity status is changed, have it repaint the entire combo. This means that you have an extra listener registered instead of having a custom repaint manager. That’s a choice you need to make based on the requirements of your specific application.