值将侦听器更改为JTextField
我希望消息框在用户更改文本字段中的值后立即出现。 目前,我需要点击回车键才能popup消息框。 我的代码有什么问题吗?
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); } } }
任何帮助将不胜感激!
将监听器添加到基础文档,该文档将自动为您创build。
// 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); } } });
通常的答案是“使用DocumentListener
”。 不过,我总是觉得界面繁琐。 事实上界面是过度devise的。 它有三种方法,用于插入,删除和replace文本,只需要一种方法:replace。 (插入可以被看作是用一些文本replace没有文本,删除可以被看作是replace一些没有文本的文本。)
通常所有你想要知道的是当文本框中的文本已经改变 ,所以一个典型的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的答案中提到的问题 ,文档有时会引发比所需更多的事件。
无论如何,这个方法可以让你replace看起来像这样的恼人的代码:
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有时可能会收到两个事件。 例如,如果用户select整个字段的内容,然后按一个键,你会收到一个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); } }
我知道这涉及到一个非常古老的问题,但是,它也引起了我一些问题。 正如kleopatra在上面的评论中回应,我用JFormattedTextField
解决了这个问题。 然而,解决scheme需要更多的工作,但更加整洁。
在字段中的每个文本更改后, JFormattedTextField
默认不会触发属性更改。 JFormattedTextField
的默认构造函数不会创build格式化程序。
但是,要执行OP所build议的操作,您需要使用格式化程序,该格式程序将在每次有效编辑该字段后调用commitEdit()
方法。 commitEdit()
方法触发了我所看到的属性更改,而不使用格式化程序,这是在焦点更改或按下Enter键时默认触发的。
有关更多详细信息,请参阅http://docs.oracle.com/javase/tutorial/uiswing/components/formattedtextfield.html#value 。
创build一个默认的格式化程序( DefaultFormatter
)对象,通过其构造函数或setter方法传递给JFormattedTextField
。 默认格式化程序的一种方法是setCommitsOnValidEdit(boolean commit)
,它设置格式化程序在每次更改文本时触发commitEdit()
方法。 这可以使用PropertyChangeListener
和propertyChange()
方法来获取。
创build一个扩展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 } });
或者你甚至可以使用lambdaexpression式:
jTextField.getDocument().addDocumentListener((SimpleDocumentListener) e -> { // Your code here });
你甚至可以使用“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) { } }
这是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); } } });
使用KeyListener(触发任何键)而不是ActionListener(在input时触发)
我是WindowBuilder的全新开发者,事实上,在几年之后,我又重新回到了Java,但是我实现了“某些东西”,然后以为我会查找并且碰到这个线程。
我正在testing这个,所以,基于所有这些都是新的,我肯定我一定会错过一些东西。
这就是我所做的,其中“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); } }
似乎到目前为止比这里更简单,似乎正在工作,但是,因为我正在写这个中间,我会很高兴听到任何被忽视的陷阱。 这是一个问题,用户可以进入和离开文本框不做改变? 我想你所做的一切都是不必要的。
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));