사용자가 텍스트 필드의 값을 변경 한 직후 메시지 상자가 나타나기를 원합니다. 현재 메시지 상자가 나타나게하려면 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);
}
}
});
답변
이에 대한 일반적인 대답은 “use DocumentListener
“입니다. 그러나 항상 인터페이스가 번거 롭다는 것을 알았습니다. 진실로 인터페이스는 오버 엔지니어링되었습니다. 텍스트를 삽입, 제거 및 대체하는 방법에는 대체 방법이 하나만 필요한 경우 세 가지가 있습니다. (삽입은 텍스트가없는 텍스트를 대체하는 것으로 볼 수 있으며 제거는 텍스트가없는 일부 텍스트를 대체하는 것으로 볼 수 있습니다.)
일반적으로 당신이 원하는 모든입니다 아는 것입니다 상자의 텍스트가 변경되었을 때 전형적인 있도록,DocumentListener
구현에는 하나의 메서드를 호출하는 세 가지 메서드가 있습니다.
따라서 다음 유틸리티 방법을 사용하여 a ChangeListener
대신보다 간단한 것을 사용할 수 있습니다 DocumentListener
. (Java 8의 람다 구문을 사용하지만 필요한 경우 오래된 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의 내용을 추적 할 수있는 방법이없는 것 같습니다. 다음은 “text”속성을 제공하는 클래스 코드입니다.
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가 제안한 작업을 수행 commitEdit()
하려면 필드를 유효하게 편집 할 때마다 메소드 를 호출하는 포맷터를 사용해야 합니다. 그만큼commitEdit()
방법은 내가 볼 수있는 것과 포맷터없이 속성 변경을 트리거하는 것입니다. 포커스 변경이나 Enter 키를 누를 때 기본적으로 트리거됩니다.
자세한 내용은 http://docs.oracle.com/javase/tutorial/uiswing/components/formattedtextfield.html#value 를 참조하십시오.
생성자 또는 setter 메소드를 통해 DefaultFormatter
전달할 기본 포맷터 ( ) 오브젝트를 작성하십시오 JFormattedTextField
. 기본 포맷터의 한 가지 방법은 텍스트가 변경 될 때마다 메소드 setCommitsOnValidEdit(boolean commit)
가 트리거되도록 포맷터를 설정하는 것 commitEdit()
입니다. 그런 다음 a PropertyChangeListener
및 propertyChange()
방법을 사용하여 선택할 수 있습니다 .
답변
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
비어 있지 않은지 확인하십시오 .
답변
문서 리스너 응용 프로그램을 사용하는 동안 실행 가능한 메소드 SwingUtilities.invokeLater ()를 사용하면 때때로 실험이 중단되고 결과를 업데이트하는 데 시간이 걸립니다. 그 대신 여기에 언급 된대로 텍스트 필드 변경 리스너에 KeyReleased 이벤트를 사용할 수도 있습니다 .
usernameTextField.addKeyListener(new KeyAdapter() {
public void keyReleased(KeyEvent e) {
JTextField textField = (JTextField) e.getSource();
String text = textField.getText();
textField.setText(text.toUpperCase());
}
});