Java 将侦听器值更改为JTextField

Java 将侦听器值更改为JTextField,java,swing,listener,jtextfield,documentlistener,Java,Swing,Listener,Jtextfield,Documentlistener,我希望消息框在用户更改文本字段中的值后立即出现。目前,我需要点击回车键来弹出消息框。我的代码有什么问题吗 textField.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent e) { if (Integer.parseInt(textField.getText())<=0){

我希望消息框在用户更改文本字段中的值后立即出现。目前,我需要点击回车键来弹出消息框。我的代码有什么问题吗

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);
        }       
    }
}
textField.addActionListener(新java.awt.event.ActionListener(){
public void actionPerformed(java.awt.event.ActionEvent e){

如果(Integer.parseInt(textField.getText())将侦听器添加到自动为您创建的基础文档中

// 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 Message",
          JOptionPane.ERROR_MESSAGE);
     }
  }
});
//侦听文本中的更改
textField.getDocument().addDocumentListener(新DocumentListener()){
公共作废更改日期(记录事件e){
警告();
}
公共作废移除更新(文档事件e){
警告();
}
公共作废插入更新(文档事件e){
警告();
}
公开无效警告(){

如果(Integer.parseInt(textField.getText())请注意,当用户修改字段时,DocumentListener有时会收到两个事件。例如,如果用户选择整个字段内容,然后按键,您将收到removeUpdate(所有内容均为remove)和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);
        }
    }
package net.yapbam.gui.widget;
导入javax.swing.JTextField;
导入javax.swing.text.AttributeSet;
导入javax.swing.text.BadLocationException;
导入javax.swing.text.PlainDocument;
/**具有映射其文本的属性的JTextField。
*
我找不到有效跟踪JTextField文本修改的方法……所以我开发了这个小部件。 *
DocumentListeners打算这样做,不幸的是,当字段中的文本被替换时,侦听器会收到两个事件: *
  • 删除替换的文本时为一个
  • *插入替换文本时,
  • 一个
  • * *第一个事件……完全是误导性的,它对应于文本中从未有过的值。 *
    DocumentListener的另一个问题是,您无法将文本修改到其中(它会引发IllegalStateException)。 *

    另一种方法是使用KeyListeners…但是一些关键事件会抛出很长时间(可能是关键帧自动重复间隔) *在释放键之后。和其他事件(例如单击OK按钮)可能会在侦听器被通知更改之前发生。 *

    此小部件保证不会引发“重影”属性更改! *@作者Jean-Marc Astesana *
    许可证:GPL v3 */ 公共类CoolJTextField扩展了JTextField{ 私有静态最终长serialVersionUID=1L; 公共静态最终字符串TEXT\u PROPERTY=“TEXT”; 公共CoolJTextField(){ 这(0); } 公共CoolJTextField(int-nbColumns){ 超级(“,NBC列); 此.setDocument(新的MyDocument()); } @抑制警告(“串行”) 私有类MyDocument扩展了PlainDocument{ 私有布尔ignoreEvents=false; @凌驾 公共void replace(整数偏移量、整数长度、字符串文本、属性集属性)引发BadLocationException{ 字符串oldValue=CoolJTextField.this.getText(); this.ignoreEvents=true; super.replace(偏移量、长度、文本、属性); this.ignoreEvents=false; String newValue=CoolJTextField.this.getText(); 如果(!oldValue.equals(newValue))CoolJTextField.this.firePropertyChange(TEXT_属性,oldValue,newValue); } @凌驾 public void remove(int offs,int len)引发BadLocationException{ 字符串oldValue=CoolJTextField.this.getText(); 超级。移除(关闭,len); String newValue=CoolJTextField.this.getText(); 如果(!ignoreEvents&&!oldValue.equals(newValue))CoolJTextField.this.firePropertyChange(TEXT_属性,oldValue,newValue); } }
    我知道这与一个非常老的问题有关,但是,它也给我带来了一些问题。正如上面的评论中所回应的,我用
    JFormattedTextField
    解决了这个问题。然而,解决方案需要更多的工作,但更整洁

    默认情况下,
    JFormattedTextField
    不会在字段中的每次文本更改后触发属性更改。
    JFormattedTextField
    的默认构造函数不会创建格式化程序

    但是,要执行OP建议的操作,您需要使用一个格式化程序,它将在每次有效编辑字段后调用
    committedit()
    方法
    方法是从我所看到的内容触发属性更改的方法,在没有格式化程序的情况下,默认情况下在焦点更改或按下enter键时触发

    有关更多详细信息,请参阅

    创建一个默认格式化程序(
    DefaultFormatter
    )对象,通过其构造函数或setter方法传递给
    JFormattedTextField
    。默认格式化程序的一个方法是
    setCommitsOnValidIt(布尔提交)
    ,它将格式化程序设置为触发
    CommittedIt()
    方法每次更改文本。然后可以使用
    PropertyChangeListener
    propertyChange()
    方法来选择该方法。

    您甚至可以使用“MouseExited”来控制。 例如:


    使用KeyListener(可在任何键上触发)而不是ActionListener(可在enter键上触发)

    这是Codemwnci的更新版本。他的代码非常好,除了错误消息外,效果非常好。为了避免错误,必须更改condition语句

      // 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);
         }
      }
    });
    

    通常的答案是“使用a”。然而,我总是觉得界面很麻烦。老实说,这个界面设计过度。它有三种方法,用于插入、删除和替换文本,而它只需要一种方法:替换(插入)
      // 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);
         }
      }
    });
    
    /**
     * 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);
    }
    
    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());
    
    @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
        }
    });
    
    jTextField.getDocument().addDocumentListener((SimpleDocumentListener) e -> {
        // Your code here
    });
    
    # 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));
    
    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();
       } 
    });
    
    import java.beans.*
    import javax.swing.*
    import javax.swing.event.*
    import javax.swing.text.*
    
    /**
     * Installs a listener to receive notification when the text of this
     * [JTextComponent] is changed. Internally, it installs a [DocumentListener] on the
     * text component's [Document], and a [PropertyChangeListener] on the text component
     * to detect if the `Document` itself is replaced.
     *
     * @param changeListener a listener to receive [ChangeEvent]s when the text is changed;
     * the source object for the events will be the text component
     */
    fun JTextComponent.addChangeListener(changeListener: ChangeListener) {
        val dl: DocumentListener = object : DocumentListener {
            private var lastChange = 0
            private var lastNotifiedChange = 0
            override fun insertUpdate(e: DocumentEvent) = changedUpdate(e)
            override fun removeUpdate(e: DocumentEvent) = changedUpdate(e)
            override fun changedUpdate(e: DocumentEvent) {
                lastChange++
                SwingUtilities.invokeLater {
                    if (lastNotifiedChange != lastChange) {
                        lastNotifiedChange = lastChange
                        changeListener.stateChanged(ChangeEvent(this))
                    }
                }
            }
        }
        addPropertyChangeListener("document") { e: PropertyChangeEvent ->
            (e.oldValue as? Document)?.removeDocumentListener(dl)
            (e.newValue as? Document)?.addDocumentListener(dl)
            dl.changedUpdate(null)
        }
        document?.addDocumentListener(dl)
    }
    
    myTextField.addChangeListener { event -> myEventHandler(event) }