1

いくつかのテキスト フィールドの内容とラジオ ボタンのペア (ボタン グループ内) の設定に基づいて検索を行う Swing プログラムがあります。特定のテキスト フィールドがフォーカスを失うと、プログラムは自動的に検索します。ラジオ ボタンの 1 つをクリックして、フォーカスを失うイベントがトリガーされると、問題が発生します。ラジオ ボタンの isSelected() の値が変更される前に、テキスト フィールドでフォーカスが失われたイベントが処理されるため、ラジオの新しい設定に基づくパラメーターではなく、「間違った」(つまり古い) パラメーターを使用して検索が行われます。ボタン。

イベント キューが落ち着いてから検索を実行するために、独自の invokeWhenIdle メソッド (以下に示す) を使用して検索を呼び出してみましたが、ラジオ ボタンの古い設定がまだ使用されています。

私の唯一の有効な解決策は、検索を実行する前に、フォーカスが失われたイベントで 250 ミリ秒遅延して、ラジオ ボタンが変更される時間を確保することです。これは機能しますが、UI の動作が遅くなります。

より良いアイデアはありますか?

public static void invokeWhenIdle(final int a_max_retry, final Runnable a_runnable) {
  if (a_max_retry <= 0) {
    throw new IllegalStateException("invokeWhenIdle: Could not run " + a_runnable);
  }

  // get the next event on the queue
  EventQueue l_queue = Toolkit.getDefaultToolkit().getSystemEventQueue();
  AWTEvent l_evt = l_queue.peekEvent();
  if (l_evt == null) {
    // nothing left on the queue (but us), we can do it
    SwingUtilities.invokeLater(a_runnable);
  } else {
    // still something in the queue, try again
    SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        invokeWhenIdle(a_max_retry - 1, a_runnable);
      }
    });
  }
}
4

1 に答える 1

1

答えではありませんが、何が起こっているのかについての説明です。多分それはアイデアを刺激するでしょう...

問題は、mousePressedがボタンモデルをアームし、mouseReleasedが実際にモデルの選択された値を変更することです。

FocusListenerコードを実行すると、モデルは未定義の状態になります。invokeLaterを使用してEDTの最後にFocusListenerコードを追加した場合でも、mouseReleasedイベントが生成される前にコードが実行されます。

以下は、これを処理するためにリスナーをコーディングする方法を示しています。ボタンの状態が変更されようとしていることを前提としています。

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class FocusSSCCE extends JPanel
{
    public FocusSSCCE()
    {
        final JRadioButton radio = new JRadioButton("Radio");
        add( radio );
        radio.setMnemonic('R');

        JTextField textField = new JTextField(10);
        add( textField );

        JButton button = new JButton("Button");
        add( button );

        textField.addFocusListener( new FocusAdapter()
        {
            public void focusLost(FocusEvent e)
            {
                boolean isSelected = radio.isSelected();

                //  Assumes selected state will change

                if (radio.getModel().isArmed())
                    isSelected = !isSelected;

                System.out.println( isSelected );
            }
        });
    }

    private static void createAndShowUI()
    {
        JFrame frame = new JFrame("FocusSSCCE");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add( new FocusSSCCE() );
        frame.pack();
        frame.setLocationRelativeTo( null );
        frame.setVisible( true );
    }

    public static void main(String[] args)
    {
        EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                createAndShowUI();
            }
        });
    }
}

ただし、このアプローチでさえも機能することを保証することはできません。何らかの理由で、ユーザーがラジオボタンでmousePressedイベントを生成し、マウスを離す前にマウスをラジオボタンから離した場合、ラジオボタンの選択された状態は変更されません。

同様に、ユーザーが理論的にはマウスを250ミリ秒以上押し続けると、誤った値が生成される可能性があるため、250ミリ秒スリープする元の実装でさえも機能することが保証されません。

これに対する私の回避策は、ラジオボタンをフォーカスできないようにすることでした。

これ以上のアプローチは考えられません。

編集:

私はただワイルドな解決策を考えました。

textField.addFocusListener( new FocusAdapter()
{
    public void focusLost(FocusEvent e)
    {
        if (e.getOppositeComponent() instanceof JRadioButton)
        {
            final JRadioButton radio = (JRadioButton)e.getOppositeComponent();

            MouseListener ml = new MouseAdapter()
            {
                public void mouseReleased(MouseEvent e)
                {
                    System.out.println( radio.isSelected() );
                    radio.removeMouseListener(this);
                }
            };

            radio.addMouseListener( ml );
        }

        else
            System.out.println( radio.isSelected() );
    }
});

基本的に、ラジオボタンをクリックしてマウスを離すまで、処理コードは実行されません。

于 2011-12-02T21:59:40.837 に答える