S40 等早期裝置系統輸入法切換繁瑣(多次按鍵切換模式)、彈出遮擋畫面、無法自定義長度/格式。直接在 Canvas 攔截按鍵碼,自行維護 StringBuffer,體驗更可控、程式碼極簡(< 50 行)。
public class NumberInputCanvas extends Canvas {
private StringBuffer buffer = new StringBuffer();
private final int MAX_LEN = 4; // 限制長度
private int lastKey = 0; // 長按檢測
protected void paint(Graphics g) {
g.setColor(0xFFFFFF); g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(0x000000);
g.drawString(buffer.toString(), getWidth()/2, getHeight()/2,
Graphics.TOP | Graphics.HCENTER);
}
protected void keyPressed(int keyCode) {
// 已滿長度:僅處理確認/取消
if (buffer.length() == MAX_LEN) {
if (keyCode == KEY_STAR) { // * 鍵確認
int value = Integer.parseInt(buffer.toString());
onNumberConfirmed(value);
}
return;
}
// 數字鍵 0-9
if (keyCode >= KEY_NUM0 && keyCode <= KEY_NUM9) {
buffer.append(keyCode - KEY_NUM0);
}
// # 鍵退格
else if (keyCode == KEY_POUND && buffer.length() > 0) {
buffer.deleteCharAt(buffer.length() - 1);
}
repaint();
}
// 長按 # 全清(需裝置支援 hasRepeatedEvents())
protected void keyRepeated(int keyCode) {
if (keyCode == KEY_POUND && buffer.length() > 0) {
buffer.setLength(0);
repaint();
}
}
// 回調介面
public void onNumberConfirmed(int number) { /* 由子類實作 */ }
}
| 常數 | 數值 | 實體鍵 |
|---|---|---|
| KEY_NUM0 | 48 | 0 |
| KEY_NUM1..9 | 49..57 | 1..9 |
| KEY_STAR | 42 | * |
| KEY_POUND | 35 | # |
注意:Canvas.getKeyCode() 回傳實體鍵碼,getGameAction() 回傳邏輯動作(UP/DOWN/FIRE),數字輸入必須用前者。
g.drawString("****", ...) 或逐字繪製 ●。buffer 存純數字,繪製時格式化。TimerTask 每 500ms 切換顯示 _ 後綴。keyRepeated 觸發時每 200ms 刪一字,而非全清。hasRepeatedEvents() 為 false 的裝置(如早期 Moto)無 keyRepeated,需提供「長按 # 2 秒全清」邏輯(自行計時)。KEY_STAR/KEY_POUND 被系統佔用(如啟動選單),需改用 FIRE 確認、BACK 退格。50 行代碼換來完全可控的數字輸入體驗,零依賴、零分配(複用 StringBuffer)、零 GC 壓力。這就是 J2ME 低級 UI 的魅力:**不用系統給的,自己造最順手的。**