JTextField限制輸入長度的完美解決方案


    關於JTextField限制輸入字符長度的問題,因為沒提供現成的api,所以我們得自己動手,來實現這個功能,網上也有很多這樣的資料,大多是在JTextField的Document的insertString方法中動手腳,比較當前文本框的字符長度和最大長度,如果輸入不涉及中文,該方法也堪稱完美了。
    細心的童鞋可能會發現,在swing里輸入中文,有的是下方彈出一個小方框,顯示當前輸入的字母;有的是直接將這些字母顯示在了文本輸入框里,打完一個字詞時,將這些字母清除掉,再將中文顯示上去。這兩種不同的顯示方式取決於System.getProperty("java.awt.im.style")的值是不是"below-the-spot",如果是,輸入框下方就顯示一個小窗口(如果為null好像也是這樣),這種情況下,上面的解決辦法也沒有問題;如果不是,即字母顯示在文本輸入框中,那么在輸入字符接近或達到最大長度時,會出現吃掉前面的字符的情況
    此問題的原因在於,在輸入中文時,將鍵入的字母(暫且稱之為“臨時字母”吧)打印在了輸入框內,假如是j,按第二個字母時(假如是i),會把之前的臨時字母(j)刪除,再用insertString插入ji,再輸入n時,把ji刪除,再插入jin,JTextField的公共方法是無法區分臨時字母的,如果插入ji時達到了長度上限,插入失敗,再輸入n,刪除ji,此時ji並未插入,所以就刪除了左邊的字符,此時就出現了吃掉左邊字符的問題。

接下來說解決辦法:
重寫Document里的方法

public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {
 if (a == null) {
  int allowCount = maxLength - getLength();
  if (allowCount > 0) {
   if (allowCount < str.length())
    str = str.substring(0, allowCount);
  } else
   return;
 }
 super.insertString(offs, str, a);
}

    經調試跟蹤,插入臨時字母時AttributeSet a都不是null,而輸入英文或中文上屏時,a都為空,所以臨時字母能夠正常插入,刪除時,就不會拿正常輸入的字符當替死鬼了。
到此,問題已經基本解決了,只是到了長度上限,還能敲入臨時字母,雖然切換輸出法、失去焦點啥的,臨時字母會自動被刪除(所以說基本沒什么問題了,除非你不是根據鼠標鍵盤操作去getText,要不getText是不會獲取到臨時字母的),但如果有點完美主義的話,心里還是有點不舒服,為啥就不能讓它在達到最大長度時,連臨時字母也不能輸入了?
    因為臨時字母的刪除再插入,在insertString、remove等處已經發生了,又不方便跟正常刪除插入進行區分,所以往上找,找到了輸入法事件處理的代碼,在此處就能比較根本地解決問題了

private int composedLen;
@Override
protected void processInputMethodEvent(InputMethodEvent e) {
 if (e.getID() == InputMethodEvent.INPUT_METHOD_TEXT_CHANGED) {
  if (e.getCommittedCharacterCount() == 0) {
   AttributedCharacterIterator aci = e.getText();
   if (getDocument().getLength() - composedLen >= maxLength) {
    e.consume();
    composedLen = 0;
   } else
    composedLen = aci != null ? aci.getEndIndex()
      - aci.getBeginIndex() : 0;
  } else
   composedLen = 0;
 }
 super.processInputMethodEvent(e);
}

    在JTextField里重寫processInputMethodEvent方法,並定義一個composedLen變量,用來記錄文本中的臨時字母的長度,文本長度減去臨時字母的長度,就得到了真正輸入的字符的長度了,如果這個長度大於等於上限,就消耗掉這個事件(e.consume()),讓它失效。介紹下里面的方法,e.getCommittedCharacterCount()得到的是提交的字符數,也就是中文上屏時,中文的字符個數,aci.getEndIndex() - aci.getBeginIndex()得到的是文本的長度,可能是上屏的中文,也可能是臨時字母。

如果你對我用insertString里的AttributeSet a是否為null作為判斷依據有所質疑的話(JDK升級后,這規則還有效嗎?),也可以把composedLen傳到insertString里,作為判斷依據。

OK,大功告成了,雖然沒寫多少內容,但找出問題和解決問題的過程,還是花了我一些時間的,有點啰嗦,就不寫了


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM