フォーカスを取得する前に、InputVerifierを使用してテキストフィールドの内容をチェックするGUIアプリケーションがあります。これはすべて非常に正常です。しかし、昨日、問題が発見されました。これはバグのようですが、どこにも言及されていません。これをバグとして報告する前に、私は尋ねると思いました:ここで明らかな何かが欠けていますか?
状況:
- InputVerifiersを使用したテキストフィールドのセット。
- すべてのコントロールでFocusLostとFocusGainedのリスナーなので、何が起こっているかを確認できます。
- 別のスレッドは、DefaultKeyboardFocusManagerを使用して、どのコントロールにフォーカスがあるかを(2秒ごとに)報告します。
- フォームの中央にあるJTextFieldに無効なデータを配置し、コントロールを離れようとしました。
マウスまたはTabキーを使用してこのコントロールから離れようとすると、移動できません。FocusLostイベントは発生せず、コントロールはフォーカスを適切に保持します。
ただし、Shift-Tabを使用してタブの逆順でコントロールから離れようとすると、FocusLostイベントが発生することがあります。これが発生した場合、別のスレッドは、フォーカスを持っているコントロールがないことを報告します。つまり、getFocusOwner()はnullを返します。
編集:以下は問題を示す小さなサンプルプログラムです。問題は余分なスレッドとは何の関係もありません-スレッドは問題をより明白にするためだけにあります。競合状態がある場合、それはSwingのどこかにあります。
問題を確認するには、2番目のテキストボックスに移動して空にします。コントロールはフォーカスを保持する必要があり、Shiftキーを押しながら離さない限りフォーカスを保持します。完全なアプリケーションとは異なり、エラーはここで100%発生するようです。これは、OpenJDK6とOracleJava7の両方に当てはまります。
これはバグになるにはほとんど明白であり、さらに複数の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);
}
}
}