Sunday, March 8, 2009

Validating And The Art Of GlassPane

The GlassPane in LWUIT is inspired by the Swing GlassPane & layered pane with quite a few twists (note: the picture on the right is of the Swing glass pane, I didn't have the energy to make one of my own)... We tried to imagine how Swing developers would have implemented the glass pane knowing what they do now about painters and Swings learning curve. But I'm getting ahead of myself, what is the glass pane?

A typical LWUIT application is essentially composed of 3 layers (this is a gross simplification though), the bg painters are responsible for drawing the background of all components including the main form. The component draws its own content which might overrule the painter and the glass pane paints last...

Essentially the glass pane is a painter that allows us to draw an overlay on top of the LWUIT application. Initially we didn't think we need a glass pane, we used to suggest that people should override the form's paint() method to reach the same result. Feel free to try and guess why this failed before reading the explanation in the next paragraph.


Overriding the paint method of a form worked initially, when you enter a form this behaves just as you would expect. However, when modifying an element within the form only that element gets repainted not the entire form! So if I had a form with a Button and text drawn on top using the Form's paint method it would get erased whenever the button got focus.

Thats good for the forms paint method, calling the forms paint method would be REALLY expensive for every little thing that occurs in LWUIT. However, we do want overlays for some things and we don't need to repaint every component in the screen to get them. The glass pane is called whenever a component gets painted, it only paints within the clipping region of the component hence it won't break the rest of the glass pane.

The painter chain is a tool that allows us to chain several painters together to perform different logistical tasks such as a validation painter coupled with a fade out painter. The sample bellow shows a crude validation panel that allows us to draw error icons next to components while exceeding their physical bounds as is common in many user interfaces

public class ValidationPane implements Painter {
private Vector components = new Vector();
private static Image error;
public ValidationPane(Form parentForm) {
try {
if(error == null) {
error = Image.createImage("/error.png");
}
} catch (IOException ex) {
ex.printStackTrace();
}
PainterChain.installGlassPane(parentForm, this);
}

public void paint(Graphics g, Rectangle rect) {
for(int iter = 0 ; iter < components.size() ; iter++) {
Component c = (Component) components.elementAt(iter);
if(c == null) {
components.removeElementAt(iter);
continue;
}
Object p = c.getClientProperty(VALIDATION_PROP);
int x = c.getAbsoluteX();
int y = c.getAbsoluteY();
x -= error.getWidth() / 2;
y += c.getHeight() - error.getHeight() / 2;
g.drawImage(error, x, y);
}
}

public void addInvalid(Component c) {
components.addElement(c);
}

public void removeInvalid(Component c) {
components.removeElement(c);
}
}

0 comments:

Post a Comment