【问题标题】:How do I know if an item of an auto-complete decorated JComboBox is mouse clicked?我如何知道自动完成装饰的 JComboBox 的项目是否被鼠标单击?
【发布时间】:2012-10-19 17:59:24
【问题描述】:

我将SwingX AutoCompleteDecorator 用于JComboBox。自动完成功能效果很好......

但我无法确定最终用户选择的时刻;很少保留我的数据。

让我试着解释一下:组合框会为每个选择触发一个“comboBoxChanged”-ActionEvent。当用户输入字符并且组合框自动匹配和选择项目时,我必须忽略这些事件。如果用户点击返回键,则会生成“comboBoxEdited”-ActionEvent,我可以保存所选值。太棒了;-)

如果使用鼠标打开JComboBox-PopUp 并选择一个项目,则唯一触发的事件是“comboBoxChanged”-ActionEvent(如自动匹配或使用光标键选择项目时)。鼠标点击事件以某种方式被消耗!?这就是我无法识别 final 鼠标选择的原因。

我该如何解决这个问题?我尝试侦听 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);
      }
    });
  }

}

【问题讨论】:

  • addItemListener(ItemListener) 时会被解雇什么?
  • @Muel - 相同的 DESELECTED- 和 SELECTED-ItemEvents 用于键盘光标导航和鼠标点击:-(
  • 我已经很长时间没有做过一些 Swing 并且我从未使用过 SwingX。我猜听一个焦点丢失事件是不可接受的?或者,您可能很幸运拥有PropertyChangeListenerVetoableChangeListener,但我在黑暗中刺伤!也许下载 SwingX 的源代码,看看他们在做什么......:P
  • 共有三种方式列出selectionlistener、swingutilities、AWTListener,我这个案例是Actionlistener更好的监听器,对于example for all (mouse & keyboard from derived jlist) event from low_level AWT listeners
  • good catch :-) But not really different compared to a plain undecorated combo when selecting the items by keyboard vs. mouse: the action is always fired when the selection changes, no support to distinguish between "final ”和“中间”的变化。

标签: java swing autocomplete jcombobox swingx


【解决方案1】:

comboBox 没有 final 选择的概念:所有选择都具有相同的语义权重,独立于它们的触发器(鼠标、键盘导航、编程、核心中的第一个字母选择)并触发 actionEvent。普通和装饰组合框的行为相同。

这正是您在大多数情况下所需要的:对选择做出反应,就像它是最终的(无论这意味着什么)

如果在您的情况下,您真的希望将 mouseEvent 触发的选择视为比其他任何触发的选择更最终(再次重申:这通常推荐用于良好的用户体验,因此在评估时要非常非常小心)您可以检查 actionEvent 返回的修饰符:

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

编辑

看到 cmets 中的用例(感谢提供它们!),意识到我的小心部分是在错误的树上吠叫 :-)

在这种情况下,鼠标手势与键盘手势确实具有不同的语义

  • 键盘:在编辑器中输入以及在弹出窗口中导航表示构建最终选择的过程,特殊键 (enter) 表示提交
  • 鼠标:点击弹窗既是选择又是提交

JComboBox 不以最佳方式支持该用例,触发太多。这甚至是内部摆动的问题,f.i.当使用组合框作为 CellEditor 时。这部分由神奇的 clientProperty 修复:

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

检测到该属性后,BasicComboBoxUI(实际上是 BasicComboPopup)keyStrokes 导航仅在弹出列表中选择,将 listSelection 的同步推迟到 comboSelection 直到通过 enter 提交。这是部分的,因为前瞻(又名:按首字母键入和选择)仍然会立即在组合中选择(并因此提交)。

简短的总结:已经有一个swing-internal用例,它导致了一个已经可用的swingx-internal解决方案,用于在表格中进行自动完成编辑——一个名为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);

【讨论】:

  • 一个很好的用例是您希望对最终选择有不同的反应,即您连接到远程服务器。如果您开始输入“htt p://ww w...”(添加空间以避免将其转换为真实链接),您很可能会使用不同的 URL 多次触发自动完成功能,并且您只想制作最终选择的连接。
  • @Robin 很好的用例——但不是特定于 autoComplete:正常的 keySelectionHandler 行为完全相同,就像使用键盘导航一样。可能值得在 SwingX 中支持,嗯……类似于 cellEditor 可能做的组合行为。
  • 我需要检查我的应用程序,我在其中使用 URL 的用例的自动完成功能,因为它存在一些可用性问题(对于最终用户和开发人员)。也许我可以在 SwingX 错误跟踪器中记录一个很好的总结 + SSCCE
  • @kleopatra - 万岁!这就是我的问题的解决方案。谢谢!我在所有事件和属性中搜索了这个 BUTTON1_MASK 信息;但我认为 getModifiers() 方法只处理修饰符 keys
  • 有关 SwingX 问题,请参阅 java.net/jira/browse/SWINGX-1532。可能其中一部分只是JComboBox 问题,但是,嘿,无论如何都记录了
猜你喜欢
  • 1970-01-01
  • 2010-12-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-12
  • 1970-01-01
  • 2012-12-07
  • 1970-01-01
相关资源
最近更新 更多