Java 防止使用重复的transferFocus()中断JTextField/JDialog

Java 防止使用重复的transferFocus()中断JTextField/JDialog,java,swing,jtextfield,jdialog,Java,Swing,Jtextfield,Jdialog,我有一个非常奇怪的场景,不幸的是,我无法阻止它发生在我的Swing应用程序中。然而,当它发生时,它对我有重大的影响。也许有人能帮忙 基本设置如下所示: Linux环境 JFrame中有多个JTextFields 按下Enter键时,JTextFields将推送transferFocus() 离开其中一个字段时会弹出一个JDialog,需要按Enter键才能将其删除 造成这一问题的情况如下: 按下回车键几秒钟 当按下enter键时,焦点显然会穿过不同的文本字段。显示该对话框时,enter键

我有一个非常奇怪的场景,不幸的是,我无法阻止它发生在我的Swing应用程序中。然而,当它发生时,它对我有重大的影响。也许有人能帮忙

基本设置如下所示:

  • Linux环境
  • JFrame中有多个JTextFields
  • 按下Enter键时,JTextFields将推送transferFocus()
  • 离开其中一个字段时会弹出一个JDialog,需要按Enter键才能将其删除
造成这一问题的情况如下:

  • 按下回车键几秒钟
当按下enter键时,焦点显然会穿过不同的文本字段。显示该对话框时,enter键将其关闭,使焦点继续在文本字段中移动。最终,在几秒钟内,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();
              }
        });
    }
}
要提前回答任何潜在问题,请执行以下操作:

  • 必须使用Enter键转移焦点
  • 输入键的垃圾邮件来自用户在键盘上留下的东西(这是在零售环境中,所以这种情况经常发生)
  • 简单地关闭和重新启动应用程序实际上不是一个选项,因为没有鼠标插入计算机。应用程序在启动时会自动启动,这使得这种情况具有破坏性,因为解决问题的唯一方法是重新启动机器
  • 这些机器的功能不是很强大(处理和内存),这在某种程度上导致问题的发生比在开发机器上重新创建时要快得多
这是Java中的一个bug吗?有人能想出一个办法来防止这种情况发生吗

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

我已经在JDK1.6、1.7和1.8中对此进行了测试。虽然在以后的版本中,文本框变得无响应需要更长的时间,但最终还是会发生这种情况

提前谢谢


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

您可以尝试跟踪上次按下Enter键的时间,并忽略在操作系统重复率范围内调用的事件。我的重复频率似乎在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();
            }
        });
    }
}

这是个好主意,谢谢!简单、整洁、有效。不幸的是,我的JDialog也使用了keylister,因为没有实际的按钮可点击,所以我扩展了您的解决方案,使用了一个“系统范围”的lastTime变量,并将相同的概念应用到我的JDialog实现中。