【发布时间】:2012-05-10 07:50:35
【问题描述】:
我有一个 GUI 应用程序,它使用 InputVerifier 在产生焦点之前检查文本字段的内容。这一切都很正常。然而,昨天发现了一个问题——它似乎是一个错误,但我在任何地方都找不到任何提及它的内容。在将其报告为错误之前,我想我会问:我在这里遗漏了一些明显的东西吗?
情况:
- 一组带有 InputVerifiers 的文本字段。
- 所有控件上的 FocusLost 和 FocusGained 侦听器,因此我可以看到发生了什么。
- 一个单独的线程使用 DefaultKeyboardFocusManager 报告(每 2 秒)哪个控件具有焦点。
- 我在表单中间的 JTextField 中放置了无效数据,并尝试离开控件。
如果我尝试使用鼠标或 Tab 键离开此控件,我将无法做到。 FocusLost 事件不会触发,并且控件正确地保留了焦点。
但是,如果我尝试使用 Shift-Tab以反向 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);
}
}
}
【问题讨论】: