在 J2ME 平台上,MIDP 定義了兩套截然不同的用戶介面 API:
Canvas 與 Graphics,專為遊戲與高度自定義介面設計,開發者需自行處理所有繪圖邏輯。兩種 API 可在同一 MIDlet 中共存,但單一 Displayable(螢幕)同一時間只能採用其中一種。命令對象(Command)是唯一可跨越兩種 API 的例外。
所有底層 UI 類別位於 javax.microedition.lcdui 套件。要使用底層 API,必須繼承 Canvas 並實作 paint(Graphics g) 方法:
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
public class MyCanvas extends Canvas {
private MIDlet midlet;
public MyCanvas(MIDlet midlet) {
this.midlet = midlet;
}
protected void paint(Graphics g) {
// 清空螢幕為白色
g.setColor(0xFFFFFF);
g.fillRect(0, 0, getWidth(), getHeight());
// 置中繪製文字
g.setColor(0x000000);
g.drawString("Hello there!", getWidth()/2, 0, Graphics.TOP | Graphics.HCENTER);
}
}
Graphics 提供了豐富的繪圖原語:drawLine、drawRect、drawArc、drawString 等,座標原點位於螢幕左上角。
在 MIDlet 的 startApp() 中透過 Display.setCurrent() 顯示 Canvas:
public class MyMIDlet extends MIDlet {
private Display display;
private MyCanvas canvas;
public MyMIDlet() {
display = Display.getDisplay(this);
canvas = new MyCanvas(this);
}
protected void startApp() {
display.setCurrent(canvas);
}
// pauseApp、destroyApp 略...
}
Canvas 提供完整的事件回呼機制:
keyPressed(int keyCode)、keyRepeated、keyReleased。keyCode 正值對應 Unicode 字元,負值為功能鍵。為消除設備差異,Canvas 定義了遊戲鍵常數(UP、DOWN、LEFT、RIGHT、FIRE 等),可透過 getKeyCode(int gameAction) 取得實際鍵碼。pointerPressed(x, y)、pointerDragged、pointerReleased。並非所有設備皆支援,需先用 hasPointerEvents() 檢測。showNotify()、hideNotify()。public abstract class GameCanvas extends Canvas {
protected MIDlet midlet;
protected int fireKey, leftKey, rightKey, upKey, downKey;
public GameCanvas(MIDlet midlet) {
this.midlet = midlet;
fireKey = getKeyCode(FIRE);
leftKey = getKeyCode(LEFT);
rightKey = getKeyCode(RIGHT);
upKey = getKeyCode(UP);
downKey = getKeyCode(DOWN);
}
}
繼承此類別即可輕鬆處理方向鍵與確認鍵:
public class MyCanvas extends GameCanvas {
private String message = "Press any key";
public MyCanvas(MIDlet midlet) { super(midlet); }
protected void paint(Graphics g) {
g.setColor(0xFFFFFF); g.fillRect(0,0,getWidth(),getHeight());
g.setColor(0x000000);
g.drawString(message, getWidth()/2, 0, Graphics.TOP|Graphics.HCENTER);
}
protected void keyPressed(int keyCode) {
if (keyCode == fireKey) message = "FIRE";
else if (keyCode == leftKey) message = "LEFT";
else if (keyCode == rightKey) message = "RIGHT";
else if (keyCode == upKey) message = "UP";
else if (keyCode == downKey) message = "DOWN";
else message = getKeyName(keyCode);
repaint();
}
}
命令(Command)封裝了動作的標籤、類型與優先序,裝置負責將其對應到實體按鍵。支援類型包括 BACK、CANCEL、EXIT、HELP、OK、SCREEN、STOP 等。優先序為正整數,1 為最高。
Command exitCmd = new Command("Exit", Command.SCREEN, 1);
canvas.addCommand(exitCmd);
canvas.setCommandListener(this); // 實作 CommandListener
CommandListener 僅定義一個方法 commandAction(Command c, Displayable d),通常由 MIDlet 主類別實作:
public class MyMIDlet extends MIDlet implements CommandListener {
// ... 建構子與 startApp 同前 ...
public void commandAction(Command c, Displayable d) {
if (c == exitCmd) { destroyApp(true); notifyDestroyed(); }
}
}
同一命令物件可被多個 Canvas 共用,高層 API 元件亦同理。
GameCanvas 封裝鍵碼映射,減少硬編碼。BACK、「確認」用 OK),提升使用者體驗一致性。