Validation overlays – the groundworks
Before i start discussing the different implementations of validation overlays that illustrate the power and flexibility of the Swing rendering pipeline, i want to mention some of the common classes that will be used throughout this series. First, here is the screenshot of the sample UI that will be used for all the techniques:
Note that the code focuses on the painting itself, and leaves the custom validation logic (based on the contents of the text field, selected combobox entry etc) to the application code (which is not relevant for discussing the Swing painting pipeline). The common classes are located in the <a href="https://pushingpixels.dev.java.net/source/browse/pushingpixels/src/org/pushingpixels/validation/">org.pushingpixels.validation</a>
and <a href="https://pushingpixels.dev.java.net/source/browse/pushingpixels/src/org/pushingpixels/validation/common/">org.pushingpixels.validation.common</a>
packages that contain the following:
- The
SampleUi
class is the UI itself. It uses the FormLayout to create a simple two-column layout with a few controls. - The
common.ValidationUtils
provides a very simple implementation of two helper methods. The first ishasError(Component c)
that returns boolean indication whether the specified component should show the error overlay. The second is thepaintErrorIcon(Component c, Graphics g, int x, int y)
that paints small error icon at the specified location. More on these two methods below. - The
ComponentVisitor
interface follows the usual visitor pattern to allow some of the discussed implementations to visit all components starting from a specific root. - The Visitor class implements the visitor pattern itself, with the
static void visit(ComponentVisitor visitor, Component c, Graphics g)
method that recursively visits the entire hierarchy of the specified component, calling the custom visitor logic on each one of the children components.
Note that the first two would be application-specific, and the last two are relevant only for some techniques.
In addition, using the visitor pattern reveals one of the weaker sides of Swing. The basic JComponent
class extends Container
, which means that every core Swing component can have children components. While it allows some nifty tricks like putting a JOGL-powered icon on a button, it unnecessarily exposes the application code to the implementation details of some more complex components. For example, an editable JComboBox
is implemented with a text field and a button. A JSpinner
is implemented as a text field and two buttons. Unfortunately, these are counted in the getComponentCount()
and returned in getComponent(int index)
, which makes it rather annoying for the visitor pattern.
Subsequently, the sample implementation of the hasError(Component c)
method in common.ValidationUtils
makes special checks when it is passed a text field. If the text field has either combobox or spinner parent, it is ignored.
The next entry will show the first extension point in the Swing rendering pipeline – the repaint manager.