我有一个 GUI 应用程序,它使用 InputVerifier 在产生焦点之前检查文本字段的内容。这一切都很正常。然而,昨天发现了一个问题——它似乎是一个错误,但我在任何地方都找不到任何提及它的内容。在我将此报告为错误之前,我想我会问:我在这里遗漏了一些明显的东西吗?
情况:
- 一组带有 InputVerifiers 的文本字段。
- 所有控件上的 FocusLost 和 FocusGained 侦听器,所以我可以看到发生了什么。
- 一个单独的线程使用 DefaultKeyboardFocusManager 报告(每 2 秒)哪个控件具有焦点。
- 我将无效数据放在表单中间的 JTextField 中,并尝试离开控件。
如果我尝试使用鼠标或使用 tab 键离开此控件,我不能。FocusLost 事件不会触发并且控件正确地保留焦点。
但是,如果我尝试使用 Shift-Tab 以相反的制表顺序离开控件,有时会触发 FocusLost 事件。如果发生这种情况,单独的线程会报告没有控件具有焦点,即 getFocusOwner() 返回 null。
编辑:下面是一个显示问题的小示例程序。问题与额外的线程无关 - 线程只是为了使问题更加明显。如果存在竞争条件,则它在 Swing 中的某个地方。
要查看问题,请转到第二个文本框并将其清空。控件应该保留焦点,除非您通过按 shift-tab 离开它,否则会保留焦点。与完整的应用程序不同,错误似乎 100% 发生在这里。在 OpenJDK 6 和 Oracle Java 7 下都是如此。
这几乎太明显了,不可能是一个错误,而且它发生在多个 Java 环境中。因此,我怀疑我遗漏了一些明显的东西。任何人?
public class FocusBugDemo extends JFrame {
static JTextField txtOne = new JTextField("Ignore this control");
static JTextField txtTwo = new JTextField("Delete this text, then press shift-tab");
static JLabel lblFocus = new JLabel("");
static KeyboardFocusManager kfm = new DefaultKeyboardFocusManager();
public static void main(String[] args) {
new FocusBugDemo();
Thread t = new Thread() {
@Override
public void run() {
while(true) {
Component c = kfm.getFocusOwner();
String focusInfo = "elsewhere";
if (c == null) { focusInfo = "null";
} else if (c == txtOne) { focusInfo = "txtOne";
} else if (c == txtTwo) { focusInfo = "txtTwo";
}
lblFocus.setText(System.currentTimeMillis() + " - Focus owner " + focusInfo);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
}
};
t.start();
}
private FocusBugDemo() {
super("Focus bug demo");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setPreferredSize(new Dimension(300,100));
setLayout(new GridLayout(3,1));
NotEmpty validator = new NotEmpty();
txtOne.setInputVerifier(validator);
txtTwo.setInputVerifier(validator);
add(txtOne);
add(txtTwo);
add(lblFocus);
pack();
setVisible(true);
}
private class NotEmpty extends InputVerifier {
@Override
public boolean verify(JComponent input) {
JTextField txtField = (JTextField) input;
return (txtField.getText().length() > 0);
}
}
}