import javax.microedition.lcdui.*;
public class MyCanvas extends Canvas {
public void paint(Graphics g) {
g.setColor(255, 0, 0);
g.fillRect(0, 0, getWidth(), getHeight( ));
g.setColor(255, 255, 255);
g.drawString("Hello World!", 0, 0, g.TOP | g.LEFT);
}
}
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class MyMidlet extends MIDlet {
public MyMidlet( ) {}
public void startApp( ) {
Canvas canvas = new MyCanvas( );
Display display = Display.getDisplay(this);
display.setCurrent(canvas);
}
public void pauseApp( ) {}
public void destroyApp(boolean unconditional) {}
}
圖1.在Canvas上繪制"Hello World!"
1. 繪圖
坐標(0,0)代表了顯示屏的左上角。X坐標的值是從左向右遞增的,Y坐標的值是從頂向下遞增的。應用程序應該一直檢查繪圖區的大小,這可以通過如下的類Canvas提供的方法實現:public int getHeight( );
public int getWidth( );
這兩個方法分別以像素值返回可顯示區的高度和寬度。
所用的繪圖模型是像素替換法--用在graphics對象中指定的當前像素值來代替目標像素值。一個24位的色彩模型由紅,綠,藍各8位(RGB)來提供。然而,由於並非所有的設備都支持彩色,應用程序中要求的顏色將被映射到設備中可用的顏色值上。但是,一個良好的應用程序,應該檢查一個設備是否支持彩色-這可以用Display類的方法isColor()和numColors( )來完成。
Graphics類提供了方法setColor()和getColor( )來設置和取得顏色。但是,不象AWT/Swing,不存在方法setBackground( )和setForeground(),所以你必須顯式地調用fillRect( )(見示例5-1)。Graphics類的大多數的另外一些方法是自解釋的,與該類的AWT版本中的方法差不多。但是,我們還是要仔細地看一下其中的幾個在環境J2ME下是如何工作的。
2. 雙緩沖
雙緩沖機制經常用來實現動畫的平滑顯示效果。在這種技術中,你不是在顯示屏上繪圖,而是繪制到顯示屏的一個拷貝上(一個脫屏的緩沖區)-它是內存的一部分。當緩沖區繪制結束,你就可以把緩沖區內容拷貝到顯示屏上。這裡的基本原理是,直接拷貝內存內容到顯示屏上要快於用原型繪制的速度。
要實現雙緩沖,可以先生成一個其尺寸與屏幕一樣的易變圖像:int width = getWidth( );
int height = getHeight( );
Image buffer = Image.createImage(width, height);
然後,取得緩沖區的圖形上下文:Graphics gc = buffer.getGraphics( );
現在,你可以在緩沖區中繪圖了:// animate
// ..
gc.drawRect(20, 20, 25, 30);
當需要把緩沖區拷貝到屏幕上時,你可以重載方法paint( )來把緩沖區內容繪制到設備顯示屏上:public void paint(Graphics g) {
g.drawImage(buffer, 0, 0, 0);
}
注意,一些MIDP實現中已經采用了雙緩沖機制,因此這裡的工作可能是不必要的。你可以使用Canvas的isDoubleBuffered( )方法來檢查是否圖形是雙緩沖方式實現的。
3. 線程問題
MIDP GUI API是線程安全的。即是說,GUI API方法可以在任何時候從任何線程中調用。唯一的例外是Canvas類的serviceRepaints( )方法,它立即調用了paint( )方法以強迫顯示的立即重繪。這是說,如果paint( )方法想在任何的應用程序調用serviceRepaints( )時已鎖定的對象上同步,應用程序將會產生死鎖。為了避免死鎖,在使用了serviceRepaints( )方法時,請不要鎖定將被paint()方法使用的對象。
另外,在所有未執行的重繪滿足後,你可以使用Display類的方法callSerially( )來執行代碼,如下所示:class TestCanvas extends Canvas implements Runnable {
void doSomething( ) {
//代碼段1
callSerially(this);
}
public void run( ) {
//代碼段2
}
}
在此,對象的run( )方法在初始化結束後被調用。
4. 字體
應用程序不能自己產生字體。代之的是,應用程序應該要求基於一些屬性(如大小,字體名稱,字形)的一種字體,底層系統將試著返回一種與要求的字體最相近的字體。Font 類用來描述各種字體和尺寸。在Font 類中一共定義了三種字體屬性,每一種屬性取值不同,如下:
屬性取值FaceMONOSPACE, PROPORTIONAL, SYSTEMSizeSMALL, MEDIUM, LARGEStyle BOLD, ITALIC, PLAIN, UNDERLINED
例如,要指定一種中等大小的字體,可以使用Font.SIZE_MEDIUM;用Font.STYLE_ITALIC來指定傾斜字形,等等。字形屬性值可以用OR(|)操作符結合;另外一些屬性值不能結合。例如:下面這種屬性值指定了一種常規,帶下劃線的字體:STYLE_PLAIN | STYLE_UNDERLINED
而,下面是非法的組合:SIZE_SMALL | SIZE_MEDIUM
下面也是非法的:FACE_SYSTEM | FACE_MONOSPACE
系統中的每種字體實際上都是分別實現的,所以為了取得描述字體的對象,可以用getFont( )方法--該方法有三個參數,分別對應字體的字面,大小和字形。如,下面的代碼以指定的字面,大小和字形屬性得到一個Font對象:Font font = Font.getFont(FACE_SYSTEM,STYLE_PLAIN, SIZE_MEDIUM);
如果沒有相匹配的字體,系統將盡可能提供最相近的匹配-總是一個有效的字體對象。
一旦得到一種字體,你就可以使用Font類的方法來檢索這種字體的信息。如,你可以用getFace(),getSize( )和getStyle( )方法來分別檢索該字體的字面,大小和字形信息。
讓我們再看一個例子:示例3中代碼子類化Canvas 類。在此,繪圖顏色設置為白色,並用該色畫出一個矩形,然後把繪圖色置為黑色。代碼剩下的部分在設備屏幕上繪制系統字體,如圖2所示。
圖2.在設備顯示屏上畫出系統字體
示例3:使用字體import javax.microedition.lcdui.*;
public class FontCanvas extends Canvas {
public void paint(Graphics g) {
g.setColor(0xffffff);
g.fillRect(0, 0, getWidth(), getHeight( ));
g.setColor(0x000000);
g.setFont(Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN,Font.SIZE_LARGE));
g.drawString("System Font", 0, 0, g.LEFT | g.TOP);
g.setFont(Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN,Font.SIZE_MEDIUM));
g.drawString("Medium Size", 0, 15, g.LEFT | g.TOP);
g.setFont(Font.getFont(Font.FACE_SYSTEM, Font.STYLE_BOLD,Font.SIZE_MEDIUM));
g.drawString("Bold Style", 0, 30, g.LEFT | g.TOP);
g.setFont(Font.getFont(Font.FACE_SYSTEM, Font.STYLE_ITALIC,Font.SIZE_MEDIUM));
g.drawString("Italic Style", 0, 45, g.LEFT | g.TOP);
g.setFont(Font.getFont(Font.FACE_SYSTEM,Font.STYLE_UNDERLINED, Font.SIZE_MEDIUM));
g.drawString("Underlined Sty