Java JTextField';s setText方法没有';我不能从键盘听者那里工作

Java JTextField';s setText方法没有';我不能从键盘听者那里工作,java,swing,jtextfield,settext,Java,Swing,Jtextfield,Settext,我不明白为什么JTextField似乎不只是通过使用setText(“”)方法来“清除”,而这是来自一个KeyListener。它在ActionListener中工作得很好,但最令人惊讶的是,如果KeyListener方法尝试调用ActionListener方法,并使用一个虚拟动作事件(作为一个简单的测试动态创建),它仍然保留键入的文本 换句话说,当您从命令行运行它时,例如,如果您在字段中键入一个“3”,您将看到setText(“test”)方法并没有像我期望的那样删除3,而是将其保留在适当的位

我不明白为什么JTextField似乎不只是通过使用setText(“”)方法来“清除”,而这是来自一个KeyListener。它在ActionListener中工作得很好,但最令人惊讶的是,如果KeyListener方法尝试调用ActionListener方法,并使用一个虚拟动作事件(作为一个简单的测试动态创建),它仍然保留键入的文本

换句话说,当您从命令行运行它时,例如,如果您在字段中键入一个“3”,您将看到setText(“test”)方法并没有像我期望的那样删除3,而是将其保留在适当的位置。然后您将在显示屏中看到“test3”。我注意到这一行并发表了评论。单击JButton将正确删除文本。JButton和JLabel将正确更改文本。但JTextField不会。如果然后按下按钮,您将看到操作事件正确地清除了JTextField。现在,如果您切换注释掉的行,您可以看到从KeyTyped方法调用actionPerformed方法的尝试!!!而且,当您在文本字段中键入“3”时,它不会被删除。我希望setText(“”)方法将其清除,但它不会。甚至当keyTyped()方法调用与JTextButton相同的actionPerformed()方法时也是如此

这里的动机可能会有所帮助。我需要捕获一个特定的热键,该热键将在键入JTextField时清除该字段,就像您按下“清除”按钮一样。这似乎不起作用

我以前没有对Swing做过那么多的工作,但这很令人费解

我的SSCCE代码如下:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;

class P2 implements KeyListener, ActionListener
{
  JTextField fld;
  JButton btn;
  JLabel  lbl;

  P2()
  {
    JFrame frm = new JFrame("Test");
           fld = new JTextField(10);
    JPanel pnl = new JPanel();
           btn = new JButton("Clear it out");
           lbl = new JLabel("This is a test");

    fld.addKeyListener(this);

    btn.addActionListener(this);

    frm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frm.setSize(400,400);
    frm.setLayout(new FlowLayout() );
    pnl.add(fld);
    pnl.add(btn);
    pnl.add(lbl);
    frm.getContentPane().add(pnl);
    frm.setVisible(true);
  }
  public void keyPressed(KeyEvent ke) {}
  public void keyReleased(KeyEvent ke) {}
  public void keyTyped(KeyEvent ke)
  {
     System.out.println("got a pressed key");

//this is the setText method that ought to wipe clean the field comments:
    this.fld.setText("test");
    this.btn.setText("try again");
    this.lbl.setText("got a presseed key");


//toggle this comment to see the invocation of the action event:
//    this.actionPerformed(new ActionEvent( new Object(), 2, "test")  );

  }
  public void actionPerformed(ActionEvent ae)
  {
     fld.setText("");
     fld.selectAll();
  }
  public static void main(String[] args)
  {
    SwingUtilities.invokeLater
    (
      new Runnable()
      {
        public void run()
        {
          new P2();
        }
      }
    );
  }
}

此行为是由于在激发
KeyListener
后,字段将处理
KeyEvent
。您可以通过以下方式规避此问题:

ke.consume();
在方法内部
键入键


根据您的要求,另一种方法是将清除调用封装在
SwingUtilities.invokeLater
中,该调用将在当前事件后处理,从而在字段更新后清除该字段。

下面是一个代码段,它使用键绑定来清除按“a”时的所有文本,实现以使用已在字段的操作映射中注册的操作(注意,您仍然需要将代码包装到SwingUtilities.invokeLater中,正如Howard已经建议的那样,以确保在字段内部处理之后对其进行处理)


不要使用keylisteners,请使用密钥绑定非常简单的修复;ke.consume()消除了这个问题。我不是100%确定这是怎么回事。。。如果在KeyListener尝试重置文本后KeyEvent继续进入JTextField,那么我猜模型会检索存储的文本吗?但是如果密钥事件被使用,那么TextField就不会实际处理该事件。那么模型是如何为未来更新的呢?我不清楚这里的流程。但非常感谢您的修复。我无法让您的代码片段正常工作——我显然需要学习关于键绑定和操作的教程。我想这是做这件事的正确方法,所以我会仔细阅读。但我完全不明白你在另一个invokeLater()中包装这个是什么意思。你的意思是把所有这些都放在主方法中吗?
    JTextField normal = new JTextField("just a normal field", 10);
    final Action selectAll = normal.getActionMap().get("select-all");
    final Action cut = normal.getActionMap().get("cut-to-clipboard");
    Action combine = new AbstractAction() {

        @Override
        public void actionPerformed(final ActionEvent e) {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    selectAll.actionPerformed(e);
                    cut.actionPerformed(e);

                }
            });
        }

    };
    normal.getActionMap().put("magic-delete-all", combine);
    normal.getInputMap().put(KeyStroke.getKeyStroke("A"), "magic-delete-all");