| 特性 | 高階 UI (List, Form, ChoiceGroup...) | 低階 UI (Canvas, Graphics) |
| 開發難度 | 低 | 高 |
| 可移植性 | 強 (由實作商適配) | 需自行處理螢幕尺寸差異 |
| 控制力 | 弱 (外觀由系統決定) | 強 (像素級控制) |
| 適用場景 | 表單、清單、一般應用 | 遊戲、自訂元件、特效介面 |
遊戲選單需求:焦點高亮、動畫、自訂版面 → **必須使用 Canvas**。
核心類別:Canvas 與 Graphics
Canvas:繪圖畫布,提供 paint(Graphics)、按鍵事件 keyPressed/Released/Repeated、遊戲動作映射 getGameAction
Graphics:畫筆,提供幾何繪製、文字、影像渲染、裁剪、色彩、字體操作
選單設計關鍵點
1. 相對座標計算 (適配多解析度)
- 項目高度 = 字體高度 + 上下 padding
- 項目寬度 = 最長文字寬度 + 左右 padding
- 選單總寬/高 = 單項尺寸 × 項目數
- 選單左上角 =
((螢幕寬 - 選單寬)/2, (螢幕高 - 選單高)/2) → 置中顯示
2. 焦點管理
- 整數變數
selected 記錄當前焦點索引 (0-based)
keyPressed 中透過 getGameAction(keyCode) 判斷 UP/DOWN/FIRE
- 索引環狀遞增/遞減:
(selected + 1) % count、(selected - 1 + count) % count
- 修改
selected 後呼叫 repaint() 觸發重繪
3. 繪製邏輯 (paint 方法)
- 清除畫面:
g.fillRect(0,0,w,h) (白底)
- 繪製外框矩形
- 繪製分隔線 (for 迴圈)
- 繪製各項目文字,焦點項目前繪製高亮背景矩形
完整原始碼:MenuCanvas.java
package com.j2medev.chapter3;
import javax.microedition.lcdui.*;
public class MenuCanvas extends Canvas {
private int selected = 0;
private int preferWidth = -1;
private int preferHeight = -1;
public static final int[] OPTIONS = {0, 1, 2, 3};
public static final String[] LABELS = {"New Game", "Settings", "High Scores", "Exit"};
public MenuCanvas() {
selected = OPTIONS[0];
// 計算項目尺寸
Font f = Font.getDefaultFont();
for (int i = 0; i < LABELS.length; i++) {
int w = f.stringWidth(LABELS[i]);
if (w > preferWidth) preferWidth = w;
}
preferWidth += 2 * 8; // 左右 padding 8px
preferHeight = f.getHeight() + 2 * 4; // 上下 padding 4px
}
protected void paint(Graphics g) {
// 保存原色
int oldColor = g.getColor();
// 清除背景 (白)
g.setColor(0xFFFFFF);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(oldColor);
// 選單幾何計算
int rectWidth = preferWidth;
int rectHeight = preferHeight * LABELS.length;
int x = (getWidth() - rectWidth) / 2;
int y = (getHeight() - rectHeight) / 2;
// 外框
g.drawRect(x, y, rectWidth, rectHeight);
// 分隔線
for (int i = 1; i < LABELS.length; i++) {
g.drawLine(x, y + preferHeight * i, x + rectWidth, y + preferHeight * i);
}
// 項目文字與焦點高亮
for (int j = 0; j < LABELS.length; j++) {
int itemY = y + j * preferHeight;
if (selected == j) {
// 高亮背景 (淺藍)
g.setColor(0x6699CC);
g.fillRect(x + 1, itemY + 1, rectWidth - 1, preferHeight - 1);
g.setColor(oldColor);
}
// 文字 (左上對齊,留 8px 左邊距, 4px 上邊距)
g.drawString(LABELS[j], x + 8, itemY + 4, Graphics.LEFT | Graphics.TOP);
}
}
protected void keyPressed(int keyCode) {
int action = getGameAction(keyCode);
switch (action) {
case Canvas.FIRE:
printLabel(selected); // 實際遊戲中這裡切換畫面
break;
case Canvas.DOWN:
selected = (selected + 1) % LABELS.length;
break;
case Canvas.UP:
selected = (selected - 1 + LABELS.length) % LABELS.length;
break;
}
repaint();
serviceRepaints(); // 強制立即重繪 (部分裝置需要)
}
// 生命週期回調示範
protected void showNotify() {
System.out.println("showNotify() called");
}
private void printLabel(int idx) {
System.out.println("Selected: " + LABELS[idx]);
}
}
進階擴充方向
| 功能 | 實作要點 |
| 焦點動畫 | 引入 focusAnimOffset,在 run() 執行緒中漸變顏色/位移,配合 repaint() |
| 二級選單 | 狀態機管理:MENU_MAIN, MENU_SETTINGS...,FIRE 切換狀態並重設 selected=0 |
| Tabbed 選單 | 頂部標籤列 + 內容區,左右鍵切換標籤,上下鍵操作內容 |
| 圖示支援 | 每項目關聯 Image,drawImage 繪製於文字左側 |
| 觸控支援 (MIDP 2.0+) | 實作 pointerPressed/Released/Dragged,計算點擊區域對應項目索引 |
效能與相容性提醒
- serviceRepaints():某些裝置 (如早期 Nokia) 若不呼叫,
repaint() 可能不會立即觸發 paint()
- 字體取得:
Font.getDefaultFont() 保證存在;自訂字體需 Font.getFont() 捕捉例外
- 影像資源:
Image.createImage("/icon.png") 放入 res/ 打包進 JAR
- 記憶體:避免在
paint() 中建立新物件 (String, Image, Font),預先建立為欄位
總結
掌握 Canvas 繪製、座標計算、焦點狀態機、按鍵映射四大核心,即可實作專業級遊戲選單。低階 UI 雖開發成本較高,但能創造高階 UI 無法實現的獨特體驗,是 J2ME 遊戲開發必備技能。
- 上一篇文章: MyEclipse J2ME 開發環境建置完整指南 (WTK + EclipseME 整合)
- 下一篇文章: J2ME 行動瀏覽器 CSS 解析器設計與實作核心原理
Copyright ©
程式碼之家 All Rights Reserved