Filthy Rich Clients
Filthy Rich Clients
Chet Haase
by Romain Guy
Filthy Rich Clients
Applications that are so graphically rich that they ooze
cool.They suck the user in from the outset and hang onto
them with a death grip of excitement.They make the user
tell their friends about the applications.
In short, they make the user actually enjoy their application
experience.
What They Have
What We Have
What You Want
What You Will Have
Demo
Agenda
• You need:
• Glass pane
• Gradients
• AlphaComposite
Glass Pane
Glass Pane
Glass Pane
class MyGlassPane extends JComponent {
@Override
protected void paintComponent(Graphics g) {
// painting jobs
}
}
Glass Pane
class MyGlassPane extends JComponent {
@Override
protected void paintComponent(Graphics g) {
// painting jobs
}
}
f.getGlassPane().setVisible(true);
Gradients
• Up to J2SE 5.0:
• java.awt.GradientPaint
• Only linear gradients
• Only two colors
• With Java SE 6:
• LinearGradientPaint and RadialGradientPaint
• Multiple stops, fraction based
Gradients
Gradients
GradientPaint p;
LinearGradientPaint p;
Graphics2D g2 = buffer.createGraphics();
g2.setComposite(AlphaComposite.DstIn);
g2.drawImage(alphaMask, null, 0, subjectHeight);
g2.dispose();
Demo
Agenda
• Fade
• Pulse
• Spring
• Morphing
Fade
• For gradual changes in UI state
• When a value is changed
• Fade in/out
• Fade from/to a color
• Opacity change
• Cross-fade
• Current value fades out
• New value fades in
Fade to Black
Fade to Black
g2.setComposite(
AlphaComposite.SrcOver.derive(getAlpha()));
g2.drawImage(glow, x, y, null);
g2.setComposite(AlphaComposite.SrcOver);
g2.drawImage(image, x, y, null);
Pulse
• Visual feedback
• For interactive elements
• On click
• On rollover
• Glasspane
Demo
Spring
Spring
int width = image.getWidth(this);
width += (int) (image.getWidth(this) *
MAGNIFY_FACTOR * getZoom());
g2.setComposite(AlphaComposite.SrcOver.derive(
1.0f - getZoom()));
g2.drawImage(image, x + bounds.x, y + bounds.y,
width, height, null);
Morphing
Graphics2D g2 = (Graphics2D) g;
g2.setPaint(gradient);
g2.fill(morph);
Morphing
Animator animator =
PropertySetter.createAnimator(
150, this, "morphing", 0.0f, 1.0f);
animator.setAcceleration(0.2f);
animator.setDeceleration(0.3f);
MouseTrigger.addTrigger(button, animator,
MouseTriggerEvent.ENTER, true);
Agenda
Graphics g = compatibleImage.getGraphics();
g.drawImage(image, 0, 0, null);
g.dispose();
return compatibleImage;
}
Loading Images
Graphics g = compatibleImage.getGraphics();
g.drawImage(image, 0, 0, null);
g.dispose();
Painting Images
• Well... Graphics.drawImage()
• Beware the fourth parameter!
• java.awt.ImageObserver
• Utterly useless with ImageIO
• Pass null instead
• Easy performance gain
Resizing Images
@Override
protected void paintComponent(Graphics g) {
g.drawImage(image, x, y, newWidth, newHeight, null);
}
Resizing Images
• Default resizing looks bad
• Use the bilinear rendering hint
• Bicubic resizing is too slow
• Bilinear is not perfect though
• Dividing the size by 2+ is similar to default resize
• Proceed step by step
• Divide only by half the size at each step
Resizing Images
int width = image.getWidth();
float ratio = (float) width / (float) image.getHeight();
BufferedImage thumb = image;
do {
width /= 2;
// ...
BufferedImage temp = new BufferedImage(width,
(int) (width / ratio),
BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = temp.createGraphics();
g2.setRenderingHint(...);
g2.drawImage(thumb, 0, 0, temp.getWidth(), temp.getHeight(), null);
g2.dispose();
thumb = temp;
} while (width != thumbWidth);
Resizing Images
// TransitionTarget implementation
Demo
Animated Transitions
Resources
• http://aerith.dev.java.net
• http://timingframework.dev.java.net
• http://www.swinglabs.org
• http://www.curious-creature.org
• http://weblogs.java.net/blog/chet
• http://www.javadesktop.org
• http://developers.sun.com/learning/javaoneonline/
The Book