使用重复transferFocus()

时间:2015-06-19 12:40:01

标签: java swing jtextfield jdialog

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

基本设置如下:

  • Linux环境。
  • JFrame中的多个JTextField。
  • 当按下Enter键时,JTextFields会通过transferFocus()。
  • 在离开其中一个字段时会弹出一个JDialog,需要按下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键转移焦点。
  • Enter键的垃圾邮件来自用户在键盘上留下的东西(这是在零售环境中,因此经常发生这种情况)。
  • 由于没有鼠标插入计算机,因此只需关闭并重新启动应用程序就不是一个选择。应用程序在启动时自动启动,使此方案具有破坏性,因为解决问题的唯一方法是重新启动计算机。
  • 这些机器并不是非常强大(处理和内存),它在某种程度上导致问题比在开发机器上重新创建时更快。

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

我可以防止这种情况发生的最接近的事情就是在关闭之前在JDialog(我的扩展)中调用sleep(500)调用,但这并不是一个很好的修复...

我已经在JDK 1.6,1.7和1.8中对此进行了测试。虽然在较新版本中文本框需要更长时间才能无响应,但它最终仍会发生。

提前致谢!

Xandel

1 个答案:

答案 0 :(得分:0)

不要使用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();
            }
        });
    }
}