防止使用重复的 transferFocus() 破坏 JTextField / JDialog
Prevent breaking of JTextField / JDialog with repeated transferFocus()
我有一个非常奇怪的场景,遗憾的是我无法阻止它在我的 Swing 应用程序中发生。但是,当它发生时,它会对我产生重大影响。也许有人可以提供帮助!
基本设置如下:
- Linux环境。
- JFrame 中的多个 JTextField。
- JTextFields 在按下 Enter 键时通过 transferFocus() 推送。
- 在留下需要按 Enter 键才能删除的字段之一时弹出 JDialog。
导致问题的情况如下:
- 按住 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
不要使用按键事件。 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();
}
});
}
}
我有一个非常奇怪的场景,遗憾的是我无法阻止它在我的 Swing 应用程序中发生。但是,当它发生时,它会对我产生重大影响。也许有人可以提供帮助!
基本设置如下:
- Linux环境。
- JFrame 中的多个 JTextField。
- JTextFields 在按下 Enter 键时通过 transferFocus() 推送。
- 在留下需要按 Enter 键才能删除的字段之一时弹出 JDialog。
导致问题的情况如下:
- 按住 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
不要使用按键事件。 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();
}
});
}
}