MIDP 將事件處理分為高級 (High-Level) 與低級 (Low-Level)兩套體系。高級面向「邏輯動作」(命令、項目值變化),低級面向「物理輸入」(鍵盤、觸控筆、繪圖)。本文逐層拆解接口、類、常量、實戰模式。
Displayable 的類 (Screen、Canvas)。setCommandListener(this) + addCommand(Command)。commandAction(Command c, Displayable d)。BACK > CANCEL > EXIT > HELP > ITEM > OK > SCREEN > STOP。Item 子類 (TextField, ChoiceGroup, Gauge 等) 的值變化。form.setItemStateListener(this)。itemStateChanged(Item item)。itemStateChanged。public class CalculatorForm extends Form implements CommandListener, ItemStateListener {
private TextField a = new TextField("A", "", 6, TextField.NUMERIC);
private TextField b = new TextField("B", "", 6, TextField.NUMERIC);
private TextField sum = new TextField("Sum", "", 6, TextField.NUMERIC | TextField.UNEDITABLE);
public CalculatorForm() {
super("Calc");
append(a); append(b); append(sum);
setItemStateListener(this);
addCommand(new Command("Exit", Command.EXIT, 1));
setCommandListener(this);
}
public void itemStateChanged(Item item) {
try {
int va = Integer.parseInt(a.getString());
int vb = Integer.parseInt(b.getString());
sum.setString(String.valueOf(va + vb));
} catch (NumberFormatException e) {
sum.setString("");
}
}
public void commandAction(Command c, Displayable d) {
if (c.getCommandType() == Command.EXIT) { /* exit */ }
}
}
Canvas 繼承 Displayable,但不允許註冊外部 Listener,必須繼承並覆寫 protected 方法:
| 方法 | 觸發條件 | 參數 | 典型用途 |
|---|---|---|---|
keyPressed(int keyCode) | 按鍵按下 | 鍵碼 (見下) | 遊戲移動、確認 |
keyReleased(int keyCode) | 按鍵釋放 | 鍵碼 | 鬆開停止移動 |
keyRepeated(int keyCode) | 長按重複 (設備支持時) | 鍵碼 | 連續移動/加速 |
pointerPressed(int x, int y) | 觸控筆/鼠標按下 | 屏幕座標 | 點擊按鈕、拖拽起點 |
pointerReleased(int x, int y) | 觸控筆抬起 | 座標 | 拖拽終點、點擊確認 |
pointerDragged(int x, int y) | 觸控筆移動 | 座標 | 滑動、繪圖 |
paint(Graphics g) | 系統請求重繪 | Graphics | 遊戲幀渲染、自定義 UI |
// 標準鍵 (所有設備必支持)
Canvas.KEY_NUM0 ... KEY_NUM9, KEY_STAR (*), KEY_POUND (#)
// 游戲鍵映射 (邏輯方向,由 getGameAction(keyCode) 轉換)
Canvas.UP, DOWN, LEFT, RIGHT, FIRE, GAME_A, GAME_B, GAME_C, GAME_D
// 檢測能力
boolean hasRepeat = hasRepeatEvents(); // 是否支持 keyRepeated
boolean hasPointer = hasPointerEvents(); // 是否支持觸控筆
boolean hasPointerMotion = hasPointerMotionEvents(); // 是否支持 pointerDragged
public class KeyTestCanvas extends Canvas {
String msg = "";
protected void paint(Graphics g) {
g.setColor(0xFFFFFF); g.fillRect(0,0,getWidth(),getHeight());
g.setColor(0); g.drawString(msg, 10, 10, 0);
g.drawString(hasRepeatEvents() ? "Repeat" : "NoRepeat", 10, 30, 0);
}
protected void keyPressed(int kc) { msg = "KP:" + kc + "(" + getGameAction(kc) + ")"; repaint(); }
protected void keyReleased(int kc) { msg = "KR:" + kc; repaint(); }
protected void keyRepeated(int kc) { msg = "KRe:" + kc; repaint(); }
}
Graphics 方法:drawLine, fillRect, drawString, drawImage, drawRegion (圖片區域/旋轉/鏡像)。Image offscreen = Image.createImage(w,h); Graphics og = offscreen.getGraphics(); → 離屏繪圖 → g.drawImage(offscreen,0,0,0); 避免閃爍。while(running) { update(); repaint(); sleep(40); } 或 Timer.schedule。| 維度 | 高級事件 | 低級事件 |
|---|---|---|
| 抽象層級 | 語義動作 (確認、取消、輸入變化) | 物理輸入 (按鍵、觸控、繪圖) |
| 可移植性 | 極高 (設備自動映射) | 需自行處理鍵碼差異、屏幕尺寸 |
| 適用場景 | 表單、列表、菜單、設置向導 | 遊戲、自定義組件、繪圖工具 |
| 代碼複雜度 | 低 | 高 (需自行管理狀態、幀循環) |
| 組合使用 | Canvas 可 addCommand 同時支持高級命令 | Screen 不支持低級回調 |
update() 或線程中。getGameAction() 統一邏輯方向,避免硬編碼鍵碼。hasPointerEvents() 守衛,不支持設備優雅降級。Image 用完 null 引用輔助 GC,Player close(),RecordStore closeRecordStore()。