import Javax.microedition.lcdui.*;
// The counter class, which can be used on a canvas
// or wrapped within a custom item.
public class CounterArea {
public static final int DEFAULT_RATE = 500;
public static final int MIN_RATE = 100;
// The callback interface by which we notify
// the counter owner of certain events.
public interface Callback {
void invalidateCounter( CounterArea counter );
void repaintCounter( CounterArea counter );
void resizeCounter( CounterArea counter );
}
public CounterArea(){
}
public CounterArea( int width, int height ){
_width = width;
_height = height;
}
public int getBackColor(){
return _backColor;
}
public Callback getCallback(){
return _callback;
}
public Font getFont(){
return _font;
}
public Font getFontForDrawing(){
return _font != null ? _font :
Font.getDefaultFont();
}
public int getHeight(){
if( _height < 0 ){
_height = getMinHeight();
}
return _height;
}
public int getMinHeight(){
return getFontForDrawing().getHeight();
}
public int getMinWidth(){
Font f = getFontForDrawing();
return f.stringWidth( Integer.toString( _value ) );
}
public int getRate(){
return _rate;
}
public int getTextColor(){
return _textColor;
}
public int getValue(){
return _value;
}
public int getWidth(){
if( _width < 0 ){
_width = getMinWidth();
}
return _width;
}
private void invalidate(){
if( _callback != null ){
_callback.invalidateCounter( this );
}
}
public boolean isCounting(){
return _timer != null;
}
public void paint( Graphics g ){
String s = Integer.toString( _value );
Font f = getFontForDrawing();
int w = f.stringWidth( s );
int h = f.getHeight();
int aw = getWidth();
int ah = getHeight();
g.setColor( _backColor );
g.fillRect( _left, _top, aw, ah );
g.setColor( _textColor );
g.drawString( s, _left + aw - w,
_top + ( ah - h ) / 2,
g.TOP | g.LEFT );
if( w > aw || h > ah ){
resize();
}
}
private void repaint(){
if( _callback != null ){
_callback.repaintCounter( this );
}
}
private void resize(){
if( _callback != null ){
_callback.resizeCounter( this );
}
}
private synchronized boolean increment( Runnable source ){
if( source != _timer ) return false;
++_value;
repaint();
return true;
}
public void setBackColor( int color ){
_backColor = color;
invalidate();
}
public void setCallback( Callback callback ){
_callback = callback;
}
public void setLeft( int left ){
_left = left;
}
public void setFont( Font f ){
_font = f;
invalidate();
}
public void setHeight( int h ){
_height = h;
}
public void setRate( int rate ){
_rate = ( rate < MIN_RATE ? MIN_RATE : rate );
}
public void setTextColor( int color ){
_textColor = color;
invalidate();
}
public void setTop( int top ){
_top = top;
}
public synchronized void setValue( int value ){
_value = value;
}
public void setWidth( int w ){
_width = w;
}
public synchronized void start(){
_timer = new CounterTimer();
new Thread( _timer ).start();
}
public synchronized void stop(){
_timer = null;
}
private int _backColor = 0x00FFFFFF;
private Callback _callback;
private Font _font;
private int _height = -1;
private int _index;
private int _left;
private int _rate = DEFAULT_RATE;
private int _textColor = 0x00000000;
private Runnable _timer;
private int _top;
private int _width = -1;
private int _value;
//-------------------------------------------------
// A very simple timer that sleeps and wakes
// up at regular intervals.
private class CounterTimer implements Runnable {
public void run(){
Thread t = Thread.currentThread();
while( true ){
try {
t.sleep( _rate );
}
catch( InterruptedException e ){
}
if( !increment( this ) ) break;
}
}
}
}
這個計數器在中垂線和橫垂線的焦點繪制計數器數值,而且可以在繪制區域尺寸太小的情況下,自動更改合適的尺寸。它同時定義了一個公有的嵌套接口,CounterArea.Callback,將組件的無效性,重繪,自適應大小傳遞給適當的控制段,一個私有的內隱類,CounterTimer,負責在後台更新計數器的數值。
CounterArea類可以直接在一個Canvas中使用,但是你也可以把它和一個定制的Item封裝在一起,外覆類,CounterItem,如下所示:
import Javax.microedition.lcdui.*;
// A custom component for MIDP 2.0 that wraps
// a CounterArea instance.
public class CounterItem extends CustomItem
implements CounterArea.Callback {
public CounterItem(){
super( null );
_area = new CounterArea();
_area.setCallback( this );
}
public Font getFont(){
return _area.getFont();
}
public int getMinContentHeight(){
return _area.getMinHeight();
}
public int getMinContentWidth(){
return _area.getMinWidth();
}
public int getPrefContentHeight( int width ){
return getMinContentHeight();
}
public int getPrefContentWidth( int height ){
return getMinContentWidth();
}
public int getValue(){
return _area.getValue();
}
protected void hideNotify(){
_area.stop();
}
public void invalidateCounter( CounterArea counter )
if( counter == _area ){
invalidate();
}
}
protected void paint( Graphics g, int width, int height ){
_area.paint( g );
}
public void repaintCounter( CounterArea counter ){
if( counter == _area ){
repaint();
}
}
public void resizeCounter( CounterArea counter ){
if( counter == _area ){
invalidate();
}
}
protected void sizeChanged( int w, int h ){
_area.setWidth( w );
_area.setHeight( h );
}
public void setFont( Font f ){
_area.setFont( f );
}
public void setValue( int value ){
_area.setValue( value );
}
protected void showNotify(){
_area.start();
}
public boolean traverse( int dir, int vw, int vh,
int[] vrect ){
return false;
}
private CounterArea _area;
}
外覆類只是起到接收回遞函數給控制段,自動開始和關閉計數器的作用,當然,任何時候如果這個Item顯示或者隱藏,你都希望能夠改變它的行為。
最後, 是一個簡單的測試 MIDlet去驗證這個計數器的作用:
import Java.io.*;
import Java.util.*;
import Javax.microedition.lcdui.*;
import Javax.microedition.midlet.*;
// A simple MIDlet to test the custom counter
// component.
public class CounterItemTest extends MIDlet
implements CommandListener {
private Display display;
public static final Command exitCommand =
new Command( "Exit",
Command.EXIT, 1 );
public CounterItemTest(){
}
public void commandAction( Command c,
Displayable d ){
if( c == exitCommand ){
exitMIDlet();
}
}
protected void destroyApp( boolean unconditional )
throws MIDletStateChangeException {
exitMIDlet();
}
public void exitMIDlet(){
notifyDestroyed();
}
public Display getDisplay(){ return display; }
protected void initMIDlet(){
Form f = new Form( "CounterItem Test" );
f.addCommand( exitCommand );
f.setCommandListener( this );
CounterItem counter = new CounterItem();
counter.setLayout( Item.LAYOUT_CENTER |
Item.LAYOUT_NEWLINE_BEFORE |
Item.LAYOUT_NEWLINE_AFTER );
f.append( counter );
getDisplay().setCurrent( f );
}
protected void pauseApp(){
}
protected void startApp()
throws MIDletStateChangeException {
if( display == null ){
display = Display.getDisplay( this );
initMIDlet();
}
}
}