Java手機軟件圖形界面API之低級GUI組件 – JAVA編程語言程序開發技術文章

 在高級API編程時,你不能控制顯示在屏幕上的內容,甚至用編程方式幾乎無法控制這些組件。由系統實現體負責選取設備的最佳顯示方式。然而,一些如遊戲類的應用程序可能需要對屏幕繪制有更多的控制。MIDP javax.microedition.lcdui包也提供瞭處理這類編程的低級API。

  為瞭在屏幕直接繪制直線,文本和形狀,你必須使用Canvas類。該類提供瞭一個MIDlet可以在其上繪制的空白屏幕。例如,在屏幕上繪制字符串”HelloWorld”。實現這個功能有一個簡單的辦法:子類化Canvas類(它是繼承自Displayable的一個抽象類)並重載paint()方法。詳見代碼段1。

  paint()方法的實現使用瞭javax.microedition.lcdui.Graphics類的繪圖功能。在方法paint()中,繪圖顏色置為紅色,然後用紅色畫一個長方形。其中,方法getWidth( )和getHeight( )分別返回Canvas對象的寬度和高度。接下來setColor( )方法把繪圖顏色設置為白色;之後,字符串”Hello World!”繪制在屏幕的左上角。

  示例1:子類化Canvas

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);
 }
}

  現在,為瞭觀看MyCanvas,必須要把實例化後進行顯示。既然Canvas是Displayable的一個子類,可以用與其它screen 類使用的同樣的setCurrent( )方法來顯示它。詳見代碼段2。

  示例2:實例化和顯示MyCanvas

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所示的效果。註意在代碼段5-1中,顏色被設置為紅色與白色,但是既然使用瞭灰度級屏幕,這裡的彩色就被映射到黑色和白色的不同的灰度級上。試著調整顯示來觀察哪一種設備的色彩顯示更好些。


圖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 類中一共定義瞭三種字體屬性,每一種屬性取值不同,如下:

屬性 取值
Face MONOSPACE, PROPORTIONAL, SYSTEM
Size SMALL, MEDIUM, LARGE
Style 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

發佈留言