【问题标题】:JTextField's setText method doesn't work from a KeyListenerJTextField 的 setText 方法在 KeyListener 中不起作用
【发布时间】:2011-09-23 06:33:54
【问题描述】:

当 JTextField 来自 KeyListener 时,为什么 JTextField 似乎不能通过对其使用 setText("") 方法来“清除”它,这让我感到困惑。它可以从 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();
        }
      }
    );
  }
}

【问题讨论】:

  • 不要使用按键监听器,使用按键绑定

标签: java swing jtextfield settext


【解决方案1】:

这种行为是由于KeyEvent 将在您的KeyListener 被触发后由该字段处理。您可以通过使用事件来规避它

ke.consume();

在你的方法中keyTyped

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

【讨论】:

  • 非常简单的修复; ke.consume() 消除了这个问题。我不是 100% 确定它是如何工作的......如果在 KeyListener 尝试重置文本后 KeyEvent 继续到 JTextField,那么我猜模型检索存储的文本?但是如果 Key Event 被消费,那么 TextField 永远不会真正处理该事件。那么模型是如何在未来得到更新的呢?我不清楚这里的流程。但是非常感谢您的修复。
【解决方案2】:

这是一个代码 sn-p 使用键绑定来清除按“a”时的所有文本,实现为使用已在字段的操作映射中注册的操作(请注意,您仍然需要将代码包装到 SwingUtilities.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");

【讨论】:

  • 我无法让您的 sn-p 工作——我显然需要学习有关键绑定和操作的教程。我认为这是执行此操作的正确方法,因此我将阅读。但是通过将它包装在另一个invokeLater()中,我完全失去了你的意思。你的意思是把所有这些都放在 Main 方法中吗?
猜你喜欢
  • 2015-02-21
  • 2021-12-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-15
  • 1970-01-01
相关资源
最近更新 更多