2

フォーカスを取得する前に、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);
        }
    }
}
4

2 に答える 2

2

現在、バグ7167871としてOracleに報告されています。

于 2012-05-12T06:24:44.820 に答える
1

あなたのsscceを使用して、@CatalinaIslandの観察をサポートするMacOS X、Java6であなたが説明した効果を再現することはできません。tab特に、フォーカスがまたはshift-tab;を使用して空のテキストフィールドを残すことはありません。フォーカスはnull、フレームが非アクティブ化されている場合にのみなります。

2つのスレッドが同期なしで複数のフィールドにアクセスしているのがわかります。少なくとも、Swingの同時実行性で説明されているように、GUIを更新するためEventQueue.invokeLater()にinを使用する必要があります。t

より広い質問はこれです:あなたはどの焦点問題を使用して解決しようとしていtますか?

import java.awt.Component;
import java.awt.DefaultKeyboardFocusManager;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.KeyboardFocusManager;
import javax.swing.InputVerifier;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;

public class FocusDemo {

    private static final JTextField txtOne =
        new JTextField("Ignore this control");
    private static final JTextField txtTwo =
        new JTextField("Delete this text, then press shift-tab");
    private static final JLabel lblFocus = new JLabel("");

    public static void main(String[] args) {
        new FocusDemo();
        Thread t = new Thread() {

            @Override
            public void run() {
                while (true) {
                    EventQueue.invokeLater(new Runnable() {

                        KeyboardFocusManager kfm =
                            new DefaultKeyboardFocusManager();

                        @Override
                        public void run() {
                            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) {
                        e.printStackTrace(System.err);
                    }
                }
            }
        };
        t.start();
    }

    private FocusDemo() {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                JFrame f = new JFrame("Focus bug demo");
                f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                f.setPreferredSize(new Dimension(300, 100));
                f.setLayout(new GridLayout(3, 1));
                NotEmpty validator = new NotEmpty();
                txtOne.setInputVerifier(validator);
                txtTwo.setInputVerifier(validator);
                f.add(txtOne);
                f.add(txtTwo);
                f.add(lblFocus);
                f.pack();
                f.setVisible(true);
            }
        });
    }

    private class NotEmpty extends InputVerifier {

        @Override
        public boolean verify(JComponent input) {
            JTextField txtField = (JTextField) input;
            return (txtField.getText().length() > 0);
        }
    }
}
于 2012-05-10T21:42:32.620 に答える