Как ждать выбора радиокнопки в случае потери фокуса - PullRequest
1 голос
/ 02 декабря 2011

У меня есть программа Swing, которая выполняет поиск по содержимому некоторых текстовых полей и настройкам пары переключателей (в группе кнопок).Программа автоматически выполнит поиск, когда некоторые текстовые поля потеряют фокус.Проблема возникает, когда событие потери фокуса вызывается нажатием на одну из переключателей.Событие потерянного фокуса в текстовом поле обрабатывается до того, как значения переключателя isSelected () переключателя изменились, поэтому поиск выполняется по «неправильным» (то есть старым) параметрам вместо параметров, основанных на новой настройке радио.button.

Я попытался вызвать поиск, используя мой собственный метод invokeWhenIdle (показанный ниже), чтобы запустить поиск после того, как очередь событий установилась, но он все еще использует старую настройку переключателей.

Мое единственное рабочее решение - задержать событие потерянного фокуса на 250 миллисекунд перед выполнением поиска, чтобы переключатели успели измениться.Это работает, но из-за этого пользовательский интерфейс выглядит вялым.

Есть идеи получше?

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);
      }
    });
  }
}

1 Ответ

1 голос
/ 03 декабря 2011

Не ответ, а объяснение того, что происходит.Возможно, это вызовет идею ...

Проблема в том, что мышь нажимает на кнопку модели кнопки, а mouseReleased фактически меняет выбранное значение модели.

Когда вы выполняете радиокнопку с кодом FocusListener, модель находится в неопределенном состоянии.Даже если вы добавите код FocusListener в конец EDT с помощью invokeLater, он все равно будет выполняться до того, как будет сгенерировано событие 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() );
    }
});

Обычно ваш код обработки не будет выполняться, пока не будет отпущена мышь, когда вы нажмете переключатель.

...