programing

JTextField로의 값 변경 리스너

nicescript 2022. 8. 9. 22:16
반응형

JTextField로의 값 변경 리스너

사용자가 텍스트 필드의 값을 변경한 후 즉시 메시지 상자가 표시되도록 합니다.현재 메시지 박스를 띄우려면 Enter 키를 눌러야 합니다.제 코드에 무슨 문제가 있나요?

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

어떤 도움이라도 주시면 감사하겠습니다!

자동으로 작성되는 기본 문서에 수신기를 추가합니다.

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

이에 대한 일반적인 대답은 "사용"입니다.하지만 저는 그 인터페이스가 항상 번거롭다고 생각합니다.사실 인터페이스는 과잉 설계되어 있습니다.이 방법에는 텍스트 삽입, 삭제 및 치환의 3가지 방법이 있습니다(삽입은 텍스트가 없는 치환으로 볼 수 있으며, 삭제는 텍스트가 없는 치환으로 볼 수 있습니다).

통상, 박스내의 텍스트가 언제 변경되었는지만 알면 됩니다.따라서, 표준적으로는,DocumentListener구현에는 1개의 메서드를 호출하는3가지 메서드가 있습니다.

그래서 나는 다음과 같은 유틸리티 방법을 만들었다. 이것은 당신이 보다 간단한 방법을 사용할 수 있게 해준다.DocumentListener구문을 에 따라 할 수 (Java 8' lamda는 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의 회답에 기재되어 있는 문제에 대응하고 있습니다.이 문제에서는, 문서가 필요한 것보다 많은 이벤트를 기동하는 경우가 있습니다.

어쨌든 이 방법을 사용하면 다음과 같은 성가신 코드를 대체할 수 있습니다.

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());

코드가 공개 도메인에 릴리스되었습니다.재미있게 보내!

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

또는 람다 식을 사용할 수도 있습니다.

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

사용자가 필드를 수정할 때 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);
        }
    }

나는 이것이 정말 오래된 문제와 관련이 있다는 것을 알지만, 그것이 나에게도 몇 가지 문제를 야기했다.클레오파트라가 위의 코멘트에서 응답한 것처럼, 저는 문제를 해결했습니다.JFormattedTextField그러나 이 솔루션은 좀 더 많은 작업이 필요하지만 더 깔끔합니다.

JFormattedTextField필드의 모든 텍스트가 변경된 후에는 기본적으로 속성 변경이 트리거되지 않습니다. .JFormattedTextField는 포메터를 작성하지 않습니다.

OP가는 OP를 .commitEdit()유효한 필드 편집 후 메서드를 지정합니다.commitEdit()method는 내가 볼 수 있는 것부터 속성 변경을 트리거하는 것입니다.포맷터가 없으면 포커스 변경 시 또는 Enter 키를 눌렀을 때 기본적으로 이 변경이 트리거됩니다.

상세한 것에 대하여는, http://docs.oracle.com/javase/tutorial/uiswing/components/formattedtextfield.html#value 를 참조해 주세요.

디폴트 포맷)을.DefaultFormatter는 " " " 에됩니다.JFormattedTextField생성자 또는 설정자 메서드를 경유합니다.의 1가지 은 " " " 입니다.setCommitsOnValidEdit(boolean commit)하여 포메터를 commitEdit()메서드를 지정합니다. 다음, 이 은 '보다 낫다'를 해서 알 수 .PropertyChangeListenerpropertyChange()★★★★★★ 。

우아한 방법은 리스너를 캐럿 위치에 추가하는 것입니다. 왜냐하면 리스너는 입력/삭제될 때마다 변경되므로 오래된 값과 현재 값을 비교하기만 하면 됩니다.

String oldVal = ""; // empty string or default value
JTextField tf = new JTextField(oldVal);

tf.addCaretListener(e -> {
    String currentVal = login.getText();

    if(!currentVal.equals(oldVal)) {
        oldVal = currentVal;
        System.out.println("Change"); // do something
    }
});

(이 이벤트는 사용자가 textField를 클릭할 때마다 트리거됩니다).

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

유저가 을, () 만, (, 저, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, an, an, an, an, an, an, an, an, an an, , an, an,Integer 것이든 수 있을 것이다.Exception s를 s로 s로 s로 s로 s로 s로 s로 s로 s로 s로 s를 s로 s로 s로 s로 s로 s로 s로 로 sJTextField을 사용하다

runnable 메서드를 사용하는 경우 Swing Utilities.Document listener 어플리케이션을 사용하는 동안 later()를 호출할 때 가끔 막히거나 결과를 갱신하는 데 시간이 걸립니다(실험 결과).대신 Key Release 이벤트를 텍스트 필드 변경 청취자에게 사용할 수도 있습니다.

usernameTextField.addKeyListener(new KeyAdapter() {
    public void keyReleased(KeyEvent e) {
        JTextField textField = (JTextField) e.getSource();
        String text = textField.getText();
        textField.setText(text.toUpperCase());
    }
});

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

"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) {

        }

    }   

ActionListener(입력 시 트리거)가 아닌 KeyListener(임의의 키로 트리거)를 사용합니다.

Document Filter?조작할 수 있는 능력을 줍니다.

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

죄송합니다. J는 Jython(자바어로는 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));

저는 Window Builder를 처음 접한 사람입니다.사실 몇 년 만에 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);
    }
}

지금까지보다 훨씬 단순하고 효과가 있는 것 같지만, 지금 쓰고 있는 중이니까 간과되고 있는 고차도 들어주시면 감사하겠습니다.사용자가 텍스트박스를 열고 나갈 수 있는 문제가 있습니까?난 네가 한 모든 것이 불필요한 임무라고 생각해.

여기 @Boann의 Kotlin 항구가 있습니다.이것은 나에게 있어서 좋은 해결책입니다.

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

그의 암호처럼, 공공 영역도 마찬가지죠

언급URL : https://stackoverflow.com/questions/3953208/value-change-listener-to-jtextfield

반응형