Value Change Listener to JTextField
我希望在用户更改文本字段中的值后立即显示消息框。 目前,我需要按Enter键才能弹出消息框。 我的代码有什么问题吗?
1 2 3 4 5 6 7 8 9 10 | 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); } } } |
任何帮助,将不胜感激!
将侦听器添加到为您自动创建的基础文档中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | // 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); } } }); |
对此的通常答案是"使用
通常,您只想知道框中文本的更改时间,因此典型的
因此,我制作了以下实用程序方法,该方法使您可以使用更简单的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | /** * 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的答案中提到的问题,该问题有时会触发比所需数量更多的事件。
无论如何,此方法可让您替换看起来像这样的烦人的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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(); } }); |
带有:
1 | addChangeListener(someTextBox, e -> doSomething()); |
代码已发布到公共领域。玩得开心!
只需创建一个扩展DocumentListener并实现所有DocumentListener方法的接口:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | @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); } } |
然后:
1 2 3 4 5 6 | jTextField.getDocument().addDocumentListener(new SimpleDocumentListener() { @Override public void update(DocumentEvent e) { // Your code here } }); |
或者甚至可以使用lambda表达式:
1 2 3 | jTextField.getDocument().addDocumentListener((SimpleDocumentListener) e -> { // Your code here }); |
请注意,当用户修改字段时,DocumentListener有时会收到两个事件。例如,如果用户选择整个字段内容,然后按一个键,您将收到一个removeUpdate(所有内容都被删除)和一个insertUpdate。
就您而言,我认为这不是问题,但总的来说是这样。
不幸的是,如果不对JTextField进行子类化,似乎无法跟踪textField的内容。
这是提供"文本"属性的类的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | 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. * I've found no way to track efficiently the modifications of the text of a JTextField ... so I developed this widget. * DocumentListeners are intended to do it, unfortunately, when a text is replace in a field, the listener receive two events: * <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. * Anoter problem with DocumentListener is that you can't modify the text into it (it throws IllegalStateException). * 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. * This widget guarantees that no"ghost" property change is thrown ! * @author Jean-Marc Astesana * 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在上面的评论中回答时,我用
默认情况下,
但是,要执行OP建议的操作,您需要使用格式化程序,该格式化程序将在每次对该字段进行有效编辑后调用
有关更多详细信息,请参见http://docs.oracle.com/javase/tutorial/uiswing/components/formattedtextfield.html#value。
创建一个默认的格式化程序(
如果我们在使用文档侦听器时使用可运行的方法SwingUtilities.invokeLater()有时会卡住,并花一些时间来更新结果(根据我的实验)。除此之外,我们还可以将KeyReleased事件用于此处所述的文本字段更改侦听器。
1 2 3 4 5 6 7 | usernameTextField.addKeyListener(new KeyAdapter() { public void keyReleased(KeyEvent e) { JTextField textField = (JTextField) e.getSource(); String text = textField.getText(); textField.setText(text.toUpperCase()); } }); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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(); } }); |
但是我不只是将用户(可能是偶然的)触摸键盘上的任何内容解析为
它是Codemwnci的更新版本。他的代码非常好,除了错误消息外,还可以正常工作。为了避免错误,您必须更改条件语句。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | // 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); } } }); |
我是WindowBuilder的新手,实际上,几年后才重新使用Java,但是我实现了"某物",然后以为我会查找并遇到这个线程。
我正在对此进行测试,因此,基于所有这些知识,我确定我一定会丢失一些东西。
这是我所做的,其中" runTxt"是一个文本框," runName"是该类的数据成员:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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); } } |
似乎比目前为止简单得多,并且似乎可以运行,但是,由于我正在撰写本文,因此,我很高兴听到任何被忽略的陷阱。用户可以在不进行更改的情况下进入和离开文本框是否有问题?我认为您所做的只是不必要的工作。
您甚至可以使用" MouseExited"进行控制。
例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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) { } } |
DocumentFilter?它使您能够进行操作。
[http://www.java2s.com/Tutorial/Java/0240__Swing/FormatJTextFieldstexttouppercase.htm]
抱歉。 J正在使用Jython(Java中的Python)-但易于理解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | # 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)); |
使用KeyListener(在任何键上触发)而不是ActionListener(在enter上触发)