在應用程式開發中經常遇到使用者輸入的問題;Sun MIDP提供了TextField控制項;這個控制項用起來不方便,一個原因是TextField的實現,不同的java虛擬機器移植,實現不同,有的java虛擬機器實現不方便,應用開發人員對此無能為力;比如我現在用的這個j2me平台,使用者輸入必須要先暫停虛擬機器,切換到另一個本地實現的視窗,輸入完畢後,再恢複虛擬機器;客戶對此抱怨很大;另一個原因是進階UI入門簡單,但要實現自己想要的功能,就顯得不靈活,而且經常會添亂。所以,我決定寫一個使用者輸入類,支援英文字元輸入和數字輸入,支援輸入模式切換,不支援漢字輸入,不需要暫停虛擬機器。而LWUIT的TextField控制項恰好實現了我想要的功能。
簡單地模仿它寫了一段測試代碼:
import javax.microedition.lcdui.Graphics;</p><p>import javax.microedition.lcdui.*;<br />import java.util.Hashtable;<br />import java.util.Vector;</p><p>public class inputCanvas extends Canvas{<br />String m_strInput = "";<br />private static Hashtable inputModes;<br />private static Vector v_InputMode = new Vector();<br />private static Object s_CurrInputMode;</p><p> private static final String[] DEFAULT_KEY_CODES = {<br /> // 0<br /> " 0",<br /> // 1<br /> ".,?!'/"1-()@/:_",<br /> // 2<br /> "ABC2",<br /> // 3<br /> "DEF3",<br /> // 4<br /> "GHI4",<br /> // 5<br /> "JKL5",<br /> // 6<br /> "MNO6",<br /> // 7<br /> "PQRS7",<br /> // 8<br /> "TUV8",<br /> // 9<br /> "WXYZ9",<br />};</p><p>private int m_iPressCount = 0;<br />private int m_iPrevKeyCode = 0;</p><p>private final static int fs_maxLength = 10;</p><p>static{<br />initInputModes();<br />}</p><p>public inputCanvas(){<br />this.setFullScreenMode(true);<br />}<br />public void paint(Graphics g){<br />g.setColor(0xFFFFFF);<br />g.fillRect(0, 0, this.getWidth(), this.getHeight());</p><p>g.setColor(0x000000);</p><p>g.drawString(m_strInput, 0, 0, Graphics.LEFT|Graphics.TOP);</p><p>g.drawString((String)s_CurrInputMode, 0, 50, Graphics.LEFT|Graphics.TOP);<br />}</p><p>protected void keyPressed(int keyCode){<br />m_iPressCount = 0;<br />m_iPrevKeyCode = keyCode;</p><p>if((keyCode >= 48)&&(keyCode <= 57)){<br />char c = getCharPerKeyCode(m_iPressCount,(keyCode-48));<br />insertChars(""+c,false);<br />}else if(keyCode == 35){<br />switchInputModes();<br />}else if(keyCode == -7){<br />deleteChar();<br />}<br />repaint();<br />}</p><p>protected void keyRepeated(int keyCode){<br />if((keyCode >= 48)&&(keyCode <= 57)&&(m_iPrevKeyCode == keyCode)){<br />m_iPressCount++;<br />char c = getCharPerKeyCode(m_iPressCount,(keyCode-48));<br />insertChars(""+c,true);<br />repaint();<br />}<br />}</p><p>protected void deleteChar(){<br />if(m_strInput.length() > 0){<br />m_strInput = m_strInput.substring(0, m_strInput.length()-1);<br />}<br />}</p><p>protected void insertChars(String c, boolean bOverWrite){</p><p>if(c == null){<br />return;<br />}<br />if(c.length() != 1){<br />return;<br />}<br />if(bOverWrite){<br />m_strInput = m_strInput.substring(0, m_strInput.length()-1)+c;<br />}else{<br />if(m_strInput.length() < fs_maxLength){<br />m_strInput = m_strInput + c;<br />}<br />}<br />}</p><p>protected char getCharPerKeyCode(int pressCount, int keyCode){</p><p>Hashtable mode = (Hashtable)inputModes.get(s_CurrInputMode);<br />String str = (String)mode.get(new Integer(keyCode+'0'));</p><p>if(str != null){<br />pressCount = pressCount%str.length();<br />return str.charAt(pressCount);<br />}<br />return 0;<br />}</p><p>private void switchInputModes(){<br />int iIndex = v_InputMode.indexOf(s_CurrInputMode);</p><p>iIndex = (iIndex+1)%v_InputMode.size();</p><p>s_CurrInputMode = v_InputMode.elementAt(iIndex);<br />}</p><p>private static void initInputModes(){<br /> if(inputModes == null) {<br /> inputModes = new Hashtable();<br /> Hashtable upcase = new Hashtable();<br /> for(int iter = 0 ; iter < DEFAULT_KEY_CODES.length ; iter++) {<br /> upcase.put(new Integer('0' + iter), DEFAULT_KEY_CODES[iter]);<br /> }</p><p> v_InputMode.addElement("ABC");<br /> inputModes.put("ABC", upcase);</p><p> Hashtable lowcase = new Hashtable();<br /> for(int iter = 0 ; iter < DEFAULT_KEY_CODES.length ; iter++) {<br /> lowcase.put(new Integer('0' + iter), DEFAULT_KEY_CODES[iter].toLowerCase());<br /> }</p><p> v_InputMode.addElement("abc");<br /> inputModes.put("abc", lowcase);</p><p> Hashtable numbers = new Hashtable();<br /> for(int iter = 0 ; iter < 10 ; iter++) {<br /> numbers.put(new Integer('0' + iter), "" + iter);<br /> }<br /> inputModes.put("123", numbers);<br /> v_InputMode.addElement("123");</p><p> s_CurrInputMode = v_InputMode.elementAt(0);<br /> }<br />}<br />}<br />
基本的原理是:
1. keyPress和keyRepeated;通過特殊的按鍵切換輸入模式、刪除索引值;我這裡沒有做游標;
2. 一種輸入模式對應一個Hashtable,然後將所有的輸入模式放在一個hashtable;根據輸入模式、索引值和按鍵次數查詢字元;
實際的效果並不好;經過測試發現,當一直按住某個鍵時,首先是keyPressed被回調,然後是keyRepeated不斷地被調用;要切換某個字元,唯一的選擇是一直按住某個鍵,直到想要的那個字元出現;而實際的情況是,按鍵的響應快過顯示結果,很難精確地在看到某個字元時釋放按鍵。
還需要改進。