JTextField 的 event 主要的有二個 CaretEvent 及 DocumentEvent。CaretEvent 用於通知感興趣的參與者事件源中的文本插入符已發生更改。DocumentEvent 用於文檔更改通知的介面。它提供一些高層級資訊,比如更改型別、在哪兒發生更改,以及更多具體的結構性更改(插入和移除哪些 Element)。

CaretListener 的 caretUpdate 主要是用於游標改變時,並不能真正得知 JTextField 內文是否有改變,所以應用上比較沒有用處。

DocumentListener 有三個方法,changedUpdate、insertUpdate、removeUpdate。insertUpdate 是當內文有新增字元時發出的通知。removeUpdate 則是當內文有字元被刪除時發出的通知。changedUpdate 卻不知有什麼用途,從沒接到這個通知,原文解譯為"給出屬性或屬性集發生了更改的通知"。

今天在做數字欄位輸入時,想要把輸入的錯誤字元刪除。於是在 insertUpdate 執行了 e.getDocument().remove(e.getOffset(), e.getLength()),卻得到 java.lang.IllegalStateException: Attempt to mutate in notification 的錯誤訊息。原意是指在事件通知期間企圖修改元件內容。我猜測應該是元件事件通知時,又呼叫修改元件內容函數,會造成再次事件通知,如此可能會陷入死循環。最後搜尋 google 發現,原來要在 event handle 裏修改元件,都要透過 SwingUtilities.invokeLater 才可以。

  • 在 DocumentListener 要取得 JTextField 的 Text 可以透過 e.getDocument().getText(0, e.getDocument().getLength())。
  • 在 DocumentListener 要刪除 JTextField 剛剛輸入的字元,可執行 e.getDocument().remove(e.getOffset(), e.getLength()),但記得要包在 SwingUtilities.invokeLater 裏面。
  • 如果好多個 JTextField 共用一個 DocumentListener 時,可以透過 JTextField.getDocument().putProperty 來設定記號,並在 DocumentListener 內利用 e.getDocument().getProperty 取得該記號來識別。
@Override public void insertUpdate(DocumentEvent e) { try { String name = (String) e.getDocument().getProperty("name"); if (name.equals("amount")) model.setIntegerValue(name, new Integer(e.getDocument().getText(0, e.getDocument().getLength()))); else model.setBillValue(name, e.getDocument().getText(0, e.getDocument().getLength())); } catch (Exception e1) { SwingUtilities.invokeLater(new Runnable() { public void run() { try { e.getDocument().remove(e.getOffset(), e.getLength()); } catch (BadLocationException e2) { e2.printStackTrace(); } } }); } }

台南小新 發表在 痞客邦 PIXNET 留言(0) 人氣()