防止使用重复的 transferFocus() 破坏 JTextField / JDialog

Prevent breaking of JTextField / JDialog with repeated transferFocus()

我有一个非常奇怪的场景,遗憾的是我无法阻止它在我的 Swing 应用程序中发生。但是,当它发生时,它会对我产生重大影响。也许有人可以提供帮助!

基本设置如下:

导致问题的情况如下:

当按下回车键时,焦点显然会飞过不同的文本字段。显示对话框时,回车键将其关闭,使焦点继续在文本字段中移动。最终,在几秒钟内,Java 中断了。文本框会立即停止响应击键——您根本无法在其中输入任何内容。除此之外,一切似乎都很正常 - 您可以四处点击并关注不同的文本框,关闭应用程序等。

我创建了一个简单的测试用例,您可以使用它来重现这种情况。

JFrame:

public class TestSwing extends JFrame {

    JTextField jtfText1, jtfText2, jtfText3;
    TextHandler handler = null;

    public TestSwing() {
        super("TextField Test Demo");
        Container container = getContentPane();
        container.setLayout(new FlowLayout());
        jtfText1 = new MyJTextField(10);
        jtfText2 = new MyJTextField(10);
        jtfText3 = new MyJTextField(10);
        container.add(jtfText1);
        container.add(jtfText2);
        container.add(jtfText3);
        handler = new TextHandler();
        jtfText3.addActionListener(handler);
        setSize(325, 100);
        setVisible(true);
    }
    private class TextHandler implements ActionListener {
        public void actionPerformed(ActionEvent e) {
            JOptionPane.showConfirmDialog(null, "wait!");
        }
    }
    public static void main(String args[]) {
        TestSwing test = new TestSwing();
        test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
}

自定义 JTextField:

public class MyJTextField extends JTextField {    
    public MyJTextField(int len) {
        super(len);
        addKeyListener(new KeyAdapter() {
              public void keyPressed(KeyEvent evt) {
                int key = evt.getKeyCode();
                if (key == KeyEvent.VK_ENTER)
                  transferFocus();
              }
        });
    }
}

预先回答任何潜在问题:

这是 Java 中的错误吗?谁能想办法防止这种情况发生?

我能防止这种情况发生的最接近的方法是在 JDialog 关闭之前调用 sleep(500)(我的已扩展),但这并不是一个很好的解决方法...

我已经在 JDK 1.6、1.7 和 1.8 中对此进行了测试。虽然在更高版本中文本框变得无响应需要更长的时间,但它最终还是会发生。

提前致谢!

Xandel

不要使用按键事件。 KeyEvents 通常用于 AWT。 Swing 有更新更好的 API 可供使用(在大多数情况下)。在这种情况下,JTextField 被设计为在按下 Enter 键时响应 ActionEvent。

您可以尝试跟踪上次按下 Enter 的时间并忽略似乎在 OS 的重复率内调用的事件。我的重复率似乎在 35 毫秒左右:

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

public class MyJTextField extends JTextField
{
    private static long lastTime = System.currentTimeMillis();

    public MyJTextField(int len)
    {
        super(len);
        addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent evt)
            {

                long diff = evt.getWhen() - lastTime;
                System.out.println(diff);

                if (diff > 50)
                {
                    transferFocus();
                }

                lastTime = evt.getWhen();
            }
        });
    }
}