我如何知道是否单击了自动完成装饰的 JComboBox 的项目? [英] How do I know if an item of an auto-complete decorated JComboBox is mouse clicked?

查看:16
本文介绍了我如何知道是否单击了自动完成装饰的 JComboBox 的项目?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我将 SwingX AutoCompleteDecorator 用于 JComboBox.自动完成功能运行良好...

I'm using the SwingX AutoCompleteDecorator for a JComboBox. The autocomplete feature works beautifully...

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

But I have trouble to identify the moment of the final user selection; to persist my data seldom.

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

Let me try to explain: The combobox fires an "comboBoxChanged"-ActionEvent for every selection. I have to ignore these events while the user is typing characters and the combobox is auto-matching and selecting items. If the user hits the return-key an "comboBoxEdited"-ActionEvent is generated and I can save the selected value. Great ;-)

如果鼠标用于打开 JComboBox-PopUp 并选择一个项目,则唯一触发的事件是comboBoxChanged"-ActionEvent(就像 auto-使用光标键匹配或选择项目).鼠标点击事件以某种方式被消耗了!?这就是为什么我无法识别 final 鼠标选择的原因.

If the mouse is used to open the JComboBox-PopUp and to select an item, the only fired event is a "comboBoxChanged"-ActionEvent (like when auto-matching or selecting an item with the cursor-keys). The mouse-clicked-Event is consumed somehow!? That's why I can't identify the final mouse selection.

我该如何解决这个问题?此 SSCCE 中记录了我尝试侦听 mouseClicked-Event 失败的尝试:

How can I figure this out? My failed attempts to listen for the mouseClicked-Event are documented in this 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);
      }
    });
  }

}

推荐答案

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

A comboBox has no notion of final selection: all selections have equal semantic weight independent on their trigger (mouse, keyboard navigation, programmatically, selection by first letter in core) and fire an actionEvent. Same behaviour for plain and decorated comboBox.

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

That's exactly what you need in most contexts: react to a selection always as if it were final (whatever that might mean)

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

If in your case you really want to regard a selection triggered by a mouseEvent as more final than those triggered by anything else (again: that's typically not recommended for a good user experience, so be very, very careful in your evaluation) you can check the modifiers returned by the actionEvent:

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

编辑

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

Seeing the use cases (thanks for providing them!) in the comments, realized that my beware partly barked at the wrong tree :-)

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

In this context, the mouse- vs. keyboard gesture have indeed different semantics

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

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

JComboBox doesn't support that use-case optimally, firing too much. That's problem even swing-internally, f.i. when using a comboBox as CellEditor. That's partly fixed by a magic clientProperty:

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

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

Detecting that property, the BasicComboBoxUI (actually the BasicComboPopup) keyStrokes navigation selects in the list of the popup only, defering the synch of the listSelection to the comboSelection until committed via enter. It's partial because the look-ahead (aka: typing and selecting by first letter) still selects (and thereby committing) immediately in the combo.

简短总结:已经有一个swing-internal用例,这导致了一个已经可用的swingx-internal解决方案,用于在表中进行自动完成编辑——一个名为ComboBoxCellEditor的类.也可以单独使用:

Short summary: there already is a swing-internal use-case, which leads to an already available swingx-internal solution for autoComplete editing in tables - a class named ComboBoxCellEditor. Can be used stand-alone also:

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

这篇关于我如何知道是否单击了自动完成装饰的 JComboBox 的项目?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆