2010-10-17 146 views
181

我希望消息框在用戶更改文本字段中的值後立即顯示。目前,我需要點擊回車鍵才能彈出消息框。我的代碼有什麼問題嗎?將值更改爲JTextField的監聽器

textField.addActionListener(new java.awt.event.ActionListener() { 
    public void actionPerformed(java.awt.event.ActionEvent e) { 

     if (Integer.parseInt(textField.getText())<=0){ 
      JOptionPane.showMessageDialog(null, 
        "Error: Please enter number bigger than 0", "Error Message", 
        JOptionPane.ERROR_MESSAGE); 
     }  
    } 
} 

任何幫助將不勝感激!

回答

315

將監聽器添加到基礎文檔,該文檔會自動爲您創建。

// Listen for changes in the text 
textField.getDocument().addDocumentListener(new DocumentListener() { 
    public void changedUpdate(DocumentEvent e) { 
    warn(); 
    } 
    public void removeUpdate(DocumentEvent e) { 
    warn(); 
    } 
    public void insertUpdate(DocumentEvent e) { 
    warn(); 
    } 

    public void warn() { 
    if (Integer.parseInt(textField.getText())<=0){ 
     JOptionPane.showMessageDialog(null, 
      "Error: Please enter number bigger than 0", "Error Massage", 
      JOptionPane.ERROR_MESSAGE); 
    } 
    } 
}); 
+0

警告/類型轉換的良好格式。同樣的模式將有助於處理雙金額(銷售數字/價格輸入或顯示) – 2014-10-13 14:31:51

+0

它工作正常,但我有一個查詢,當我插入一些文本在文本字段中,然後我想調用一個方法。我不知道它是如何完成的。 – 2015-03-14 11:21:43

+0

當我點擊另一個表格單元格時,我遇到了JTable沒有從可編輯的JComboBox獲取文本框更新的問題,並且這裏的insertUpdate函數是使它正常工作的唯一方法。 – winchella 2015-10-07 17:42:06

14

要知道,當用戶修改字段,則可以的DocumentListener,有時,接受兩個事件。例如,如果用戶選擇整個字段內容,然後按一個鍵,您將收到一個removeUpdate(所有內容都被刪除)和一個insertUpdate。 就你而言,我不認爲這是一個問題,但一般來說,它是。 不幸的是,沒有子類化JTextField,似乎沒有辦法跟蹤textField的內容。 這裏是提供一個「文本」屬性的一類代碼:

package net.yapbam.gui.widget; 

import javax.swing.JTextField; 
import javax.swing.text.AttributeSet; 
import javax.swing.text.BadLocationException; 
import javax.swing.text.PlainDocument; 

/** A JTextField with a property that maps its text. 
* <br>I've found no way to track efficiently the modifications of the text of a JTextField ... so I developed this widget. 
* <br>DocumentListeners are intended to do it, unfortunately, when a text is replace in a field, the listener receive two events:<ol> 
* <li>One when the replaced text is removed.</li> 
* <li>One when the replacing text is inserted</li> 
* </ul> 
* The first event is ... simply absolutely misleading, it corresponds to a value that the text never had. 
* <br>Anoter problem with DocumentListener is that you can't modify the text into it (it throws IllegalStateException). 
* <br><br>Another way was to use KeyListeners ... but some key events are throw a long time (probably the key auto-repeat interval) 
* after the key was released. And others events (for example a click on an OK button) may occurs before the listener is informed of the change. 
* <br><br>This widget guarantees that no "ghost" property change is thrown ! 
* @author Jean-Marc Astesana 
* <BR>License : GPL v3 
*/ 

public class CoolJTextField extends JTextField { 
    private static final long serialVersionUID = 1L; 

    public static final String TEXT_PROPERTY = "text"; 

    public CoolJTextField() { 
     this(0); 
    } 

    public CoolJTextField(int nbColumns) { 
     super("", nbColumns); 
     this.setDocument(new MyDocument()); 
    } 

    @SuppressWarnings("serial") 
    private class MyDocument extends PlainDocument { 
     private boolean ignoreEvents = false; 

     @Override 
     public void replace(int offset, int length, String text, AttributeSet attrs) throws BadLocationException { 
      String oldValue = CoolJTextField.this.getText(); 
      this.ignoreEvents = true; 
      super.replace(offset, length, text, attrs); 
      this.ignoreEvents = false; 
      String newValue = CoolJTextField.this.getText(); 
      if (!oldValue.equals(newValue)) CoolJTextField.this.firePropertyChange(TEXT_PROPERTY, oldValue, newValue); 
     } 

     @Override 
     public void remove(int offs, int len) throws BadLocationException { 
      String oldValue = CoolJTextField.this.getText(); 
      super.remove(offs, len); 
      String newValue = CoolJTextField.this.getText(); 
      if (!ignoreEvents && !oldValue.equals(newValue)) CoolJTextField.this.firePropertyChange(TEXT_PROPERTY, oldValue, newValue); 
     } 
    } 
+2

Swing已經_has_類型的文本字段,將文檔更改映射到屬性 - 它被稱爲JFormattedTextField :-) – kleopatra 2012-12-23 09:05:30

10

我知道這涉及到一個真正的老問題,但是,它給我帶來了一些問題了。由於kleopatra在上面的評論中回覆,我用JFormattedTextField解決了問題。然而,解決方案需要更多的工作,但更加簡潔。

JFormattedTextField默認情況下不會在字段中的每個文本更改後觸發屬性更改。 JFormattedTextField的默認構造函數不會創建格式化程序。

但是,要執行OP所建議的操作,您需要使用格式器,該格式器將在每次有效編輯字段後調用commitEdit()方法。 commitEdit()方法是觸發屬性更改從我可以看到和沒有格式化程序,這是默認情況下觸發焦點更改或按Enter鍵時。

有關更多詳細信息,請參見http://docs.oracle.com/javase/tutorial/uiswing/components/formattedtextfield.html#value

通過其構造函數或setter方法創建一個默認格式化程序(DefaultFormatter)對象以傳遞給JFormattedTextField。默認格式化程序的一種方法是setCommitsOnValidEdit(boolean commit),它會在每次更改文本時將格式化程序設置爲觸發commitEdit()方法。然後可以使用PropertyChangeListenerpropertyChange()方法來獲取。

1

甚至可以使用「MouseExited」來控制。 例如:

private void jtSoMauMouseExited(java.awt.event.MouseEvent evt) {          
     // TODO add your handling code here: 
     try { 
      if (Integer.parseInt(jtSoMau.getText()) > 1) { 
       //auto update field 
       SoMau = Integer.parseInt(jtSoMau.getText()); 
       int result = SoMau/5; 

       jtSoBlockQuan.setText(String.valueOf(result)); 
      } 
     } catch (Exception e) { 

     } 

    } 
+3

不是真的:需求正在做一些事情_when文本被更改後 - - 這與mouseEvents無關; - ) – kleopatra 2013-10-21 09:51:20

0

使用的KeyListener(觸發上的任意鍵),而不是的ActionListener(觸發上輸入)

+0

這不起作用,因爲該字段的值未被正確捕獲,'field.getText()'返回初始值。和事件('arg0.getKeyChar()')返回按鍵錯誤檢查,以確定是否應該連接字段文本。 – psycotik 2016-02-19 19:00:27

1

這是Codemwnci的更新版本。他的代碼非常好,除了錯誤消息外,它的工作很棒。爲避免錯誤,您必須更改條件語句。

// Listen for changes in the text 
textField.getDocument().addDocumentListener(new DocumentListener() { 
    public void changedUpdate(DocumentEvent e) { 
    warn(); 
    } 
    public void removeUpdate(DocumentEvent e) { 
    warn(); 
    } 
    public void insertUpdate(DocumentEvent e) { 
    warn(); 
    } 

    public void warn() { 
    if (textField.getText().length()>0){ 
     JOptionPane.showMessageDialog(null, 
      "Error: Please enter number bigger than 0", "Error Massage", 
      JOptionPane.ERROR_MESSAGE); 
    } 
    } 
}); 
+0

只要任何長度超過length = 0的字符串輸入到文本字段中,您的改編就會觸發錯誤消息對話框。所以這基本上是一個空字符串以外的任何字符串。這不是所要求的解決方案。 – klaar 2017-11-07 13:08:23

35

通常的答案是「使用DocumentListener」。不過,我總是覺得界面繁瑣。事實上界面過度設計。它有三種方法,用於插入,刪除和替換文本,但只需要一種方法:替換。(插入可以被看作是用一些文本替換沒有文本,並且刪除可以被看作是替換一些沒有文本的文本。)

通常所有你想要知道的是當文本在該框已更改爲,因此典型的DocumentListener實現具有調用一種方法的三種方法。

因此,我提出了以下實用方法,它可以讓您使用更簡單的ChangeListener而不是DocumentListener。 (它使用Java 8的lambda語法,但如果需要的話,你能適應它的Java類。)

/** 
* Installs a listener to receive notification when the text of any 
* {@code JTextComponent} is changed. Internally, it installs a 
* {@link DocumentListener} on the text component's {@link Document}, 
* and a {@link PropertyChangeListener} on the text component to detect 
* if the {@code Document} itself is replaced. 
* 
* @param text any text component, such as a {@link JTextField} 
*  or {@link JTextArea} 
* @param changeListener a listener to receieve {@link ChangeEvent}s 
*  when the text is changed; the source object for the events 
*  will be the text component 
* @throws NullPointerException if either parameter is null 
*/ 
public static void addChangeListener(JTextComponent text, ChangeListener changeListener) { 
    Objects.requireNonNull(text); 
    Objects.requireNonNull(changeListener); 
    DocumentListener dl = new DocumentListener() { 
     private int lastChange = 0, lastNotifiedChange = 0; 

     @Override 
     public void insertUpdate(DocumentEvent e) { 
      changedUpdate(e); 
     } 

     @Override 
     public void removeUpdate(DocumentEvent e) { 
      changedUpdate(e); 
     } 

     @Override 
     public void changedUpdate(DocumentEvent e) { 
      lastChange++; 
      SwingUtilities.invokeLater(() -> { 
       if (lastNotifiedChange != lastChange) { 
        lastNotifiedChange = lastChange; 
        changeListener.stateChanged(new ChangeEvent(text)); 
       } 
      }); 
     } 
    }; 
    text.addPropertyChangeListener("document", (PropertyChangeEvent e) -> { 
     Document d1 = (Document)e.getOldValue(); 
     Document d2 = (Document)e.getNewValue(); 
     if (d1 != null) d1.removeDocumentListener(dl); 
     if (d2 != null) d2.addDocumentListener(dl); 
     dl.changedUpdate(null); 
    }); 
    Document d = text.getDocument(); 
    if (d != null) d.addDocumentListener(dl); 
} 

不同於直接添加監聽到的文件,這個處理您安裝一個新的文檔(罕見)情況下,對象在文本組件上。此外,它還可以解決Jean-Marc Astesana's answer中提到的問題,其中文檔有時引發的事件超過了需要。

無論如何,這種方法可以讓你更換惱人的代碼看起來像這樣:

someTextBox.getDocument().addDocumentListener(new DocumentListener() { 
    @Override 
    public void insertUpdate(DocumentEvent e) { 
     doSomething(); 
    } 

    @Override 
    public void removeUpdate(DocumentEvent e) { 
     doSomething(); 
    } 

    @Override 
    public void changedUpdate(DocumentEvent e) { 
     doSomething(); 
    } 
}); 

搭配:發佈到公共領域

addChangeListener(someTextBox, e -> doSomething()); 

代碼。玩的開心!

+2

類似的解決方案:創建一個'抽象類DocumentChangeListener實現DocumentListener',並使用另一個抽象方法'change(DocumentEvent e)',您可以從其他所有3種方法中調用該方法。對我來說似乎更加明顯,因爲它使用或多或少與'abstract * Adapter'偵聽器相同的邏輯。 – geronimo 2016-12-22 18:31:11

+0

+1作爲'changedUpdate'方法將通過'insertUpdate'和'removeUpdate'中的每個調用顯式調用,以使其工作。 – Kais 2017-12-01 14:12:44

0

我是WindowBuilder的新成員,事實上,在幾年之後纔回到Java,但是我實現了「某些東西」,然後以爲我會查找它並碰到這個線程。

我正在測試這個,所以,基於對所有這些都是新手,我相信我一定會錯過一些東西。

這裏就是我所做的,其中「runTxt」是一個文本框和「runName」是類的數據成員:

public void focusGained(FocusEvent e) 
    { 
    if (e.getSource() == runTxt) 
     { 
     System.out.println("runTxt got focus"); 
     runTxt.selectAll(); 
     } 
    } 
public void focusLost(FocusEvent e) 
    { 
    if (e.getSource() == runTxt) 
     { 
     System.out.println("runTxt lost focus"); 
     if(!runTxt.getText().equals(runName))runName= runTxt.getText(); 
     System.out.println("runText.getText()= " + runTxt.getText() + "; runName= " + runName); 
     } 
    } 

似乎比到目前爲止什麼是這裏簡單了很多,似乎是工作,但是,由於我正在寫這篇文章,所以我很希望聽到任何被忽視的陷阱。用戶是否可以輸入&讓文本框無法進行更改?我認爲你所做的一切都是不必要的任務。

7

只是箱子擴展的DocumentListener並實現所有的DocumentListener方法的接口:

@FunctionalInterface 
public interface SimpleDocumentListener extends DocumentListener { 
    void update(DocumentEvent e); 

    @Override 
    default void insertUpdate(DocumentEvent e) { 
     update(e); 
    } 
    @Override 
    default void removeUpdate(DocumentEvent e) { 
     update(e); 
    } 
    @Override 
    default void changedUpdate(DocumentEvent e) { 
     update(e); 
    } 
} 

然後:

jTextField.getDocument().addDocumentListener(new SimpleDocumentListener() { 
    @Override 
    public void update(DocumentEvent e) { 
     // Your code here 
    } 
}); 

,或者你甚至可以使用lambda表達式:

jTextField.getDocument().addDocumentListener((SimpleDocumentListener) e -> { 
    // Your code here 
}); 
+0

不要忘記,此解決方案需要抽象類而不是接口在Java 8之前的所有版本中。 – klaar 2017-11-07 13:05:24

-1

DocumentFilter ?它給你操縱的能力。

[http://www.java2s.com/Tutorial/Java/0240__Swing/FormatJTextFieldstexttouppercase.htm]

對不起。Ĵ我用Jython(在Java中的Python) - 但很容易理解

# python style 
# upper chars [ text.upper() ] 

class myComboBoxEditorDocumentFilter(DocumentFilter): 
def __init__(self,jtext): 
    self._jtext = jtext 

def insertString(self,FilterBypass_fb, offset, text, AttributeSet_attrs): 
    txt = self._jtext.getText() 
    print('DocumentFilter-insertString:',offset,text,'old:',txt) 
    FilterBypass_fb.insertString(offset, text.upper(), AttributeSet_attrs) 

def replace(self,FilterBypass_fb, offset, length, text, AttributeSet_attrs): 
    txt = self._jtext.getText() 
    print('DocumentFilter-replace:',offset, length, text,'old:',txt) 
    FilterBypass_fb.replace(offset, length, text.upper(), AttributeSet_attrs) 

def remove(self,FilterBypass_fb, offset, length): 
    txt = self._jtext.getText() 
    print('DocumentFilter-remove:',offset, length, 'old:',txt) 
    FilterBypass_fb.remove(offset, length) 

// (java style ~example for ComboBox-jTextField) 
cb = new ComboBox(); 
cb.setEditable(true); 
cbEditor = cb.getEditor(); 
cbEditorComp = cbEditor.getEditorComponent(); 
cbEditorComp.getDocument().setDocumentFilter(new myComboBoxEditorDocumentFilter(cbEditorComp)); 
0
textBoxName.getDocument().addDocumentListener(new DocumentListener() { 
    @Override 
    public void insertUpdate(DocumentEvent e) { 
     onChange(); 
    } 

    @Override 
    public void removeUpdate(DocumentEvent e) { 
     onChange(); 
    } 

    @Override 
    public void changedUpdate(DocumentEvent e) { 
     onChange(); 
    } 
}); 

但我不會只是解析他的任何鍵盤上(也許事故)觸摸用戶爲Integer。你應該抓住任何Exception,並確保JTextField不是空的。