Last Updated: January 31, 1997
The Problem
One of the issues with the 1.0 AWT is that creating new components requires
creating subclasses of java.awt.Canvas or java.awt.Panel, which means that each new
component owns its own opaque native window.
This one-to-one mapping between components and native windows results in three problems:
The advantages of creating lightweight components are the following:
We are using this framework in an upcoming version of the toolkit (beyond 1.1) to implement pure-java versions of the base UI controls (Button, List, etc.) which implement a common look-and-feel across the platforms (and don't use the native peers).
public class DoubleBufferPanel extends Panel {
Image offscreen;
/**
* null out the offscreen buffer as part of invalidation
*/
public void invalidate() {
super.invalidate();
offscreen = null;
}
/**
* override update to *not* erase the background before painting
*/
public void update(Graphics g) {
paint(g);
}
/**
* paint children into an offscreen buffer, then blast entire image
* at once.
*/
public void paint(Graphics g) {
if(offscreen == null) {
offscreen = createImage(getSize().width, getSize().height);
}
Graphics og = offscreen.getGraphics();
og.setClip(0,0,getSize().width, getSize().height);
super.paint(og);
g.drawImage(offscreen, 0, 0, null);
og.dispose();
}
}
import java.lang.*;
import java.util.*;
import java.awt.*;
import java.awt.event.*;
/**
* RoundButton - a class that produces a lightweight button.
*/
public class RoundButton extends Component {
String label; // The Button's text
protected boolean pressed = false; // true if the button is detented.
/**
* Constructs a RoundButton with the specified label.
* @param label the label of the button
*/
public RoundButton(String label) {
this.label = label;
enableEvents(AWTEvent.MOUSE_EVENT_MASK);
}
/**
* paints the RoundButton
*/
public void paint(Graphics g) {
int s = Math.min(getSize().width - 1, getSize().height - 1);
// paint the interior of the button
if(pressed) {
g.setColor(getBackground().darker().darker());
} else {
g.setColor(getBackground());
}
g.fillArc(0, 0, s, s, 0, 360);
// draw the perimeter of the button
g.setColor(getBackground().darker().darker().darker());
g.drawArc(0, 0, s, s, 0, 360);
// draw the label centered in the button
Font f = getFont();
if(f != null) {
FontMetrics fm = getFontMetrics(getFont());
g.setColor(getForeground());
g.drawString(label,
s/2 - fm.stringWidth(label)/2,
s/2 + fm.getMaxDescent());
}
}
/**
* The preferred size of the button.
*/
public Dimension getPreferredSize() {
Font f = getFont();
if(f != null) {
FontMetrics fm = getFontMetrics(getFont());
int max = Math.max(fm.stringWidth(label) + 40, fm.getHeight() + 40);
return new Dimension(max, max);
} else {
return new Dimension(100, 100);
}
}
/**
* The minimum size of the button.
*/
public Dimension getMinimumSize() {
return new Dimension(100, 100);
}
/**
* Paints the button and distribute an action event to all listeners.
*/
public void processMouseEvent(MouseEvent e) {
Graphics g;
switch(e.getID()) {
case MouseEvent.MOUSE_PRESSED:
// render myself inverted....
pressed = true;
// Repaint might flicker a bit. To avoid this, you can use
// double buffering (see the Gauge example).
repaint();
break;
case MouseEvent.MOUSE_RELEASED:
// render myself normal again
if(pressed == true) {
pressed = false;
// Repaint might flicker a bit. To avoid this, you can use
// double buffering (see the Gauge example).
repaint();
}
break;
case MouseEvent.MOUSE_ENTERED:
break;
case MouseEvent.MOUSE_EXITED:
if(pressed == true) {
// Cancel! Don't send action event.
pressed = false;
// Repaint might flicker a bit. To avoid this, you can use
// double buffering (see the DoubleBufferPanel example above).
repaint();
// Note: for a more complete button implementation,
// you wouldn't want to cancel at this point, but
// rather detect when the mouse re-entered, and
// re-highlight the button. There are a few state
// issues that that you need to handle, which we leave
// this an an excercise for the reader (I always
// wanted to say that!)
}
break;
}
super.processMouseEvent(e);
}
}