繼承 `Canvas` (或 `GameCanvas`),在 `paint()` 繪製輸入框,在 `keyPressed()` 直接處理數字鍵 `KEY_NUM0`~`KEY_NUM9`,**完全繞過系統輸入法**,體驗媲美原生應用。
import javax.microedition.lcdui.*;
public class NumberInputCanvas extends Canvas {
private StringBuffer inputBuffer = new StringBuffer(); // 輸入緩衝
private int maxLength = 4; // 最大長度
private int lastKey = -1; // 最後按鍵 (長按檢測用)
// 顏色常數
private static final int BG_COLOR = 0xFFFFFF;
private static final int TEXT_COLOR = 0x000000;
private static final int BORDER_COLOR = 0x888888;
private static final int CURSOR_COLOR = 0xFF0000;
public NumberInputCanvas() {
setFullScreenMode(false);
}
/** 設定最大輸入長度 */
public void setMaxLength(int len) {
this.maxLength = len;
}
/** 取得輸入內容 */
public String getInput() {
return inputBuffer.toString();
}
/** 清空輸入 */
public void clear() {
inputBuffer.setLength(0);
repaint();
}
protected void paint(Graphics g) {
int w = getWidth();
int h = getHeight();
// 背景
g.setColor(BG_COLOR);
g.fillRect(0, 0, w, h);
// 邊框
g.setColor(BORDER_COLOR);
g.drawRect(0, 0, w - 1, h - 1);
// 文字內容置中顯示
g.setColor(TEXT_COLOR);
String text = inputBuffer.toString();
int textW = g.getFont().stringWidth(text);
int textH = g.getFont().getHeight();
g.drawString(text, (w - textW) / 2, (h - textH) / 2, Graphics.TOP | Graphics.LEFT);
// 閃爍游標 (簡易:根據時間奇偶顯示)
if ((System.currentTimeMillis() / 500) % 2 == 0 && text.length() < maxLength) {
g.setColor(CURSOR_COLOR);
int cursorX = (w - textW) / 2 + textW + 2;
int cursorY = (h - textH) / 2;
g.drawLine(cursorX, cursorY, cursorX, cursorY + textH);
}
}
protected void keyPressed(int keyCode) {
int gameAction = getGameAction(keyCode);
// 數字鍵 0-9 直接追加
if (keyCode >= Canvas.KEY_NUM0 && keyCode <= Canvas.KEY_NUM9) {
if (inputBuffer.length() < maxLength) {
char digit = (char) ('0' + (keyCode - Canvas.KEY_NUM0));
inputBuffer.append(digit);
repaint();
}
return;
}
// 退格鍵 (通常是 # 鍵或左軟鍵)
if (keyCode == Canvas.KEY_POUND || gameAction == Canvas.LEFT) {
if (inputBuffer.length() > 0) {
inputBuffer.deleteCharAt(inputBuffer.length() - 1);
repaint();
}
return;
}
// 確認/提交 (通常是 * 鍵、右軟鍵、選擇鍵、FIRE)
if (keyCode == Canvas.KEY_STAR || gameAction == Canvas.FIRE || gameAction == Canvas.RIGHT) {
if (inputBuffer.length() > 0) {
int number = Integer.parseInt(inputBuffer.toString());
onInputConfirmed(number); // 回調處理
}
return;
}
// 長按 # 鍵清空 (需裝置支援 hasRepeatedEvents)
if (keyCode == Canvas.KEY_POUND && hasRepeatedEvents()) {
// 實際長按邏輯在 keyRepeated 處理
}
}
protected void keyRepeated(int keyCode) {
// 長按 # 鍵:清空全部
if (keyCode == Canvas.KEY_POUND && inputBuffer.length() > 0) {
inputBuffer.setLength(0);
repaint();
}
}
/** 輸入確認回調,子類覆寫或設定 Listener */
protected void onInputConfirmed(int number) {
System.out.println("輸入確認: " + number);
// 實際應用:切換畫面、發送指令、驗證密碼等
}
}
| 技術點 | 說明 |
|---|---|
| 直接判斷 `KEY_NUM0`~`KEY_NUM9` | 繞過輸入法,單次按鍵即輸入一個數字,零延遲 |
| `StringBuffer` 緩衝 | 高效字串拼接,避免 `String` 不可變產生大量臨時物件 |
| `getGameAction()` 跨平台映射 | 將裝置特定鍵碼映射為標準遊戲動作 (LEFT, RIGHT, FIRE 等),提升相容性 |
| 閃爍游標 | `System.currentTimeMillis() / 500 % 2` 簡易實現 500ms 閃爍 |
| `hasRepeatedEvents()` 檢測 | **關鍵**:並非所有裝置支援 `keyRepeated`,必須檢查後再依賴長按邏輯 |
| 回調模式 `onInputConfirmed` | 解耦輸入元件與業務邏輯,支援繼承覆寫或 Listener 模式 |
private boolean passwordMode = false;
public void setPasswordMode(boolean enabled) {
this.passwordMode = enabled;
}
protected void paint(Graphics g) {
// ...
String displayText = passwordMode ?
new String(new char[inputBuffer.length()]).replace('\0', '*') :
inputBuffer.toString();
// 繪製 displayText...
}
// 自動插入分隔符
if (inputBuffer.length() == 2 || inputBuffer.length() == 5) { // HH:MM:SS
inputBuffer.append(':');
}
// 顯示時用 formatText,實際值用 rawBuffer
// 輸入超過可見寬度時,左側截斷顯示 "...4567"
int visibleChars = getWidth() / g.getFont().charWidth('0');
String displayText = inputBuffer.length() > visibleChars ?
"..." + inputBuffer.substring(inputBuffer.length() - visibleChars + 3) :
inputBuffer.toString();
// 需 MIDP 2.0 + MMAPI
try {
Player player = Manager.createPlayer("device:vibrator");
player.start(); // 短震動確認按鍵
} catch (Exception e) { /* 忽略 */ }
J2ME 低級 UI 自繪數字輸入框,**核心優勢在於「直接響應硬體鍵盤」**:
這是 J2ME 時代「因限制而生的創新」典範——**當高級 API 不夠好時,低級 API 給你完全的自由**。同樣的思想在現代 Android `View` 自定義、iOS `UIView` 繪製、Web Canvas 渲染、嵌入式裸機 UI 開發中依然閃耀。