Как узнать, щелкнут ли элемент автозаполнения декорированного JComboBox?

Я использую SwingX AutoCompleteDecorator для JComboBox. Функция автозаполнения работает прекрасно...

Но мне трудно определить момент окончательного выбора пользователя; сохранять мои данные редко.

Позвольте мне попытаться объяснить: поле со списком запускает «comboBoxChanged»-ActionEvent для каждого выбора. Я должен игнорировать эти события, пока пользователь вводит символы, а поле со списком автоматически сопоставляет и выбирает элементы. Если пользователь нажимает клавишу возврата, генерируется "comboBoxEdited"-ActionEvent, и я могу сохранить выбранное значение. Здорово ;-)

Если мышь используется для открытия JComboBox-PopUp и выбора элемента, единственным генерируемым событием является "comboBoxChanged"-ActionEvent (например, при автоматическом сопоставлении или выборе элемента с помощью клавиш курсора). Событие щелчка мышью каким-то образом потребляется !? Вот почему я не могу определить последний выбор мыши.

Как я могу понять это? Мои неудачные попытки прослушать событие mouseClicked-Event задокументированы в этом SSCCE:

import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import org.jdesktop.swingx.autocomplete.AutoCompleteDecorator;


public class SearchForThePopUpMouseClick extends JPanel
{
  private JComboBox<String> comboBox;

  public SearchForThePopUpMouseClick()
  {
    comboBox = new JComboBox<String>(new String[] { "Anna", "Marc", "Maria", "Marten", "Peter" });
    add(comboBox);
    add(new JTextField("textfield to click"));

    AutoCompleteDecorator.decorate(comboBox);


    comboBox.addActionListener(new ActionListener()
    {
      @Override
      public void actionPerformed(ActionEvent e)
      {
        System.out.println("Action Event with '" + e.getActionCommand() + " " + e.getID() + "'");
      };
    });


    ((Component) comboBox.getUI().getAccessibleChild(comboBox, 0)).addMouseListener(new MouseListener()
    {
      @Override
      public void mouseReleased(MouseEvent e)
      {
        System.out.println(e);
      }
      @Override
      public void mousePressed(MouseEvent e)
      {
        System.out.println(e);
      } 
      @Override
      public void mouseExited(MouseEvent e)
      {
        System.out.println(e);
      }
      @Override
      public void mouseEntered(MouseEvent e)
      {
        System.out.println(e);
      }
      @Override
      public void mouseClicked(MouseEvent e)
      {
        System.out.println(e);
      }
    });
  }


  public static void main(String[] args) throws Exception
  {
    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
    SwingUtilities.invokeLater(new Runnable()
    {
      @Override
      public void run()
      {
        SearchForThePopUpMouseClick autoCompletePanel = new SearchForThePopUpMouseClick();
        JFrame frame = new JFrame("SwingX Autocomplete Example");
        frame.add(autoCompletePanel);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
      }
    });
  }

}

person bobndrew    schedule 30.10.2012    source источник
comment
Что срабатывает, когда вы addItemListener(ItemListener) ?   -  person Muel    schedule 30.10.2012
comment
@Muel — те же DESELECTED- и SELECTED-ItemEvents для навигации с помощью курсора клавиатуры и кликов мышью :-(   -  person bobndrew    schedule 30.10.2012
comment
Я давно не пробовал Swing и никогда не использовал SwingX. Я предполагаю, что прослушивание события потери фокуса неприемлемо? В качестве альтернативы, вам может повезти с PropertyChangeListener или VetoableChangeListener, но я колю в темноте! Возможно, загрузите исходный код SwingX и посмотрите, что они делают... :P   -  person Muel    schedule 30.10.2012
comment
есть три способа listselectionlistener, swingutilities, AWTListener, в этом случае я лучше слушаю Actionlistener, для примера для всех (мышь и клавиатура из производного jlist) событие от прослушивателей low_level AWT   -  person mKorbel    schedule 30.10.2012
comment
хороший улов :-) Но на самом деле не отличается от простого неукрашенного комбо при выборе элементов с помощью клавиатуры и мыши: действие всегда запускается при изменении выбора, нет поддержки для различения окончательного и промежуточного изменения.   -  person kleopatra    schedule 30.10.2012


Ответы (1)


ComboBox не имеет понятия окончательного выбора: все варианты выбора имеют одинаковый семантический вес независимо от их триггера (мышь, навигация с помощью клавиатуры, программно, выбор по первой букве в ядре) и запускают событие actionEvent. Такое же поведение для простого и декорированного поля со списком.

Это именно то, что вам нужно в большинстве случаев: реагировать на выбор всегда так, как если бы он был окончательным (что бы это ни значило)

Если в вашем случае вы действительно хотите рассматривать выбор, вызванный событием мыши, как более окончательный, чем выбор, вызванный чем-либо еще (опять же: это обычно не рекомендуется для хорошего взаимодействия с пользователем , так что будьте очень, очень осторожны в своих оценках) вы можете проверить модификаторы, возвращаемые actionEvent:

if ((e.getModifiers() & InputEvent.BUTTON1_MASK) != 0) {
    // triggered by mouse
}

Изменить

Увидев варианты использования (спасибо за их предоставление!) в комментариях, понял, что мой остерегайтесь частично не того дерева :-)

В этом контексте жесты мыши и клавиатуры действительно имеют разную семантику.

  • клавиатура: ввод в редакторе, а также навигация во всплывающем окне обозначают процесс создания окончательного выбора со специальной клавишей (ввод), обозначающей фиксацию
  • мышь: щелчок во всплывающем окне одновременно выбирает и фиксирует

JComboBox не поддерживает этот вариант использования оптимальным образом, вызывая слишком много срабатывания. Это проблема даже внутри качелей, т.е. при использовании comboBox в качестве CellEditor. Это частично исправлено волшебным clientProperty:

public DefaultCellEditor(final JComboBox comboBox) {
    editorComponent = comboBox;
    comboBox.putClientProperty("JComboBox.isTableCellEditor", Boolean.TRUE);

Обнаружив это свойство, навигация BasicComboBoxUI (фактически BasicComboPopup) keyStrokes выбирает только в списке всплывающего окна, откладывая синхронизацию listSelection с comboSelection до тех пор, пока не будет зафиксировано с помощью ввода. Это частично, потому что просмотр вперед (он же: ввод и выбор по первой букве) по-прежнему выбирает (и тем самым фиксирует) сразу в комбо.

Краткая сводка: уже есть вариант использования swing-internal, который приводит к уже доступному решению для редактирование autoComplete в таблицах — класс ComboBoxCellEditor. Также можно использовать отдельно:

AutoCompleteDecorator.decorate( withEditor );
ComboBoxCellEditor editor = new ComboBoxCellEditor(withEditor);
CellEditorListener listener = new CellEditorListener() {

    @Override
    public void editingStopped(ChangeEvent e) {
        // do commit stuff
    }

    @Override
    public void editingCanceled(ChangeEvent e) {
    }
};
editor.addCellEditorListener(listener);
contentPane.add(withEditor, BorderLayout.SOUTH);
person kleopatra    schedule 30.10.2012
comment
Хороший вариант использования, когда вам нужна другая реакция на окончательный выбор, — это подключение к удаленному серверу. Если вы начнете вводить htt p://ww w... (добавил пробел, чтобы избежать преобразования его в настоящую ссылку), вы, скорее всего, несколько раз активируете функцию автозаполнения с разными URL-адресами, и вы хотите установить соединение только на окончательный выбор. - person Robin; 30.10.2012
comment
@Robin хороший вариант использования, но не специфичный для автозаполнения: обычный keySelectionHandler ведет себя точно так же, как и навигация с помощью клавиатуры. Возможно, стоит поддержать в SwingX, хм ... что-то вроде поведения комбо, как может сделать cellEditor. - person kleopatra; 30.10.2012
comment
Мне нужно проверить свое приложение, в котором я использую эту функцию автозаполнения с вариантом использования URL-адресов, поскольку у него есть некоторые проблемы с удобством использования (как для конечного пользователя, так и для разработчика). Возможно, я смогу записать хорошее резюме + SSCCE в трекер ошибок SwingX. - person Robin; 30.10.2012
comment
@kleopatra - ура! Это решение моей проблемы. Спасибо! Я искал все события и свойства для этой информации BUTTON1_MASK; но я думал, что метод getModifiers() работает только с модификаторами keys. - person bobndrew; 30.10.2012
comment
@Robin & kleopatra - мой вариант использования - сохранение данных с использованием (возможно) медленного вызова службы. Таким образом, выбор, вызванный mouseClick, не должен быть более окончательным, чем что-либо еще, он должен быть таким же окончательным, как выбор клавиши ввода. Дополнительное примечание: существует также различное поведение fireEvent между наведением мыши на элементы открытого всплывающего окна со списком (элементы выбираются визуально, но нет itemChanged- или actionEvent) и "хождением" по элементы с клавишами курсора (запускаются itemChanged и actionEvent). Это поведение вызвано не AutoCompleteDecorator, а проявляется вместе с ним. :-) - person bobndrew; 30.10.2012
comment
triggered by a mouseClick should not be more final than anything else затем используйте вместо этого ListSelectionListener, эта строка кода может быть для JTableHeader - person mKorbel; 30.10.2012
comment
@mKorbel - Что такое JTableHeader? Я сдаюсь, сдаюсь, капитулирую, сдаюсь и сдаюсь. Ты победил! ;-) - person bobndrew; 30.10.2012
comment
JTableHeader - person mKorbel; 30.10.2012
comment
См. java.net/jira/browse/SWINGX-1532, чтобы узнать о проблеме с SwingX. Вероятно, часть этого просто проблема JComboBox, но эй, все равно зарегистрировал ее - person Robin; 30.10.2012