从 JComboBox 弹出窗口中获取当前突出显示的项目(未选中的项目)

Posted

技术标签:

【中文标题】从 JComboBox 弹出窗口中获取当前突出显示的项目(未选中的项目)【英文标题】:Obtain currently highlighted item from JComboBox popup (not selected item) 【发布时间】:2013-04-02 10:33:29 【问题描述】:

我希望能够在 JComboBox 下拉列表中当前突出显示的项目更改时做出反应。请注意,我不是在寻找一种方法来获取当前选定的项目,而是突出显示的项目。当鼠标悬停在此弹出窗口上时,它会突出显示鼠标位置处的项目,但这不会影响当前选定的项目,因此我不能简单地通过 ItemListenerActionListener 收听来实现我想要的。

我正在尝试创建一个由JComboBox 和耦合工具提示组成的组件,该工具提示显示当前突出显示的项目的附加信息(文档)。

作为我的第一次尝试,我正在向我的构造函数添加一些代码(扩展 JComboBox):

import java.awt.BorderLayout;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.accessibility.AccessibleContext;
import javax.accessibility.AccessibleState;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.SwingUtilities;
import javax.swing.plaf.basic.ComboPopup;

public class SomeFrame extends JFrame 

    private MyComboBox combo;

    public SomeFrame() 
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        setSize(100,20);
        setLocationRelativeTo(null);
        setLayout(new BorderLayout());
        combo = new MyComboBox();        
        combo.setModel(new DefaultComboBoxModel(new String[]"one", "two", "three", "four"));
        add(combo);
        pack();
    

    public static void main(String[] args) 
        SwingUtilities.invokeLater(new Runnable() 

            public void run() 
                SomeFrame frame = new SomeFrame();
                frame.setVisible(true);
            
        );
        

    // this is the important part
    private static class MyComboBox extends JComboBox 

        public MyComboBox() 
            getAccessibleContext().addPropertyChangeListener(new PropertyChangeListener() 
                public void propertyChange(PropertyChangeEvent evt) 
                    if (AccessibleContext.ACCESSIBLE_STATE_PROPERTY.equals(evt.getPropertyName())
                            && AccessibleState.FOCUSED.equals(evt.getNewValue())
                            && getAccessibleContext().getAccessibleChild(0) instanceof ComboPopup) 
                        ComboPopup popup = (ComboPopup) getAccessibleContext().getAccessibleChild(0);
                        JList list = popup.getList();
                        System.out.println("--> " + String.valueOf(list.getSelectedValue()));
                    
                
            );
        
    


它似乎有效,但我通过一些阴暗的渠道和试验/错误得到了这段代码,所以我认为必须有更好的方法来做到这一点。有任何想法吗?上面的代码甚至是生产安全的吗?

【问题讨论】:

我最终选择了 kelopatra 的建议。我的问题可能有点误导,因为我提到了工具提示,却忘了提到我将来可能会切换到其他更灵活的组件。 你解决了吗?我正在创建的组合中遇到类似的问题。我只想获取弹出列表中标记的项目:github.com/kl0ck/searchcombobox/commit/… @ceklock 看看 kleopatra 在下面接受的答案中提出了什么建议。 【参考方案1】:

我正在尝试创建一个由 JComboBox 和耦合工具提示组成的组件

为组合框创建自定义渲染器。然后在渲染器中使用 setToolTipText(...) 方法。

JTable 教程中的Specifying Tool Tips For Cells 部分展示了如何对表执行此操作。组合框渲染器的概念应该相同。

【讨论】:

如果我没记错的话,这将不允许我以我喜欢的方式定位工具提示。但这会比我现在所做的要好得多。我会试一试的。感谢您对自定义渲染器的建议。【参考方案2】:

很好的问题和很好的解决方案 - 除了在可访问组合中似乎存在错误,它不会更新其在 updateUI 上的内部接线,即在切换 LAF 时:

列表的可访问选择更改由注册到 comboPopup 列表的内部 ListSelectionListener 触发 comboPopup 由 ui-delegate 控制并在 installUI 中重新/创建 accessibleCombo 不会将其内部列表更新为新创建和安装的列表

您对此无能为力。所以我会直接听列表选择,然后您可以完全控制 LAF 更改的重新布线:

public static class XComboBox extends JComboBox 

    private ListSelectionListener listener;

    public XComboBox() 
        uninstall();
        install();
    

    @Override
    public void updateUI() 
        uninstall();
        super.updateUI();
        install();
    

    private void uninstall() 
        if (listener == null) return;
        getPopupList().removeListSelectionListener(listener);
        listener = null;
    

    protected void install() 
        listener = new ListSelectionListener() 
            @Override
            public void valueChanged(ListSelectionEvent e) 
                if (e.getValueIsAdjusting()) return;

                JList list = getPopupList();
                System.out.println("--> " + String.valueOf(list.getSelectedValue()));
            
        ;
        getPopupList().addListSelectionListener(listener);
    

    private JList getPopupList() 
        ComboPopup popup = (ComboPopup) getUI().getAccessibleChild(this, 0);
        return popup.getList();

    

【讨论】:

我根本不知道这个错误。大多数时候,我倾向于远离任何与 LAF 相关的事情。如果我无法提交自定义渲染器解决方案,我也会尝试这样做。谢谢。

以上是关于从 JComboBox 弹出窗口中获取当前突出显示的项目(未选中的项目)的主要内容,如果未能解决你的问题,请参考以下文章

在当前弹出窗口中显示错误消息(从数据库中获取记录)

如何更改焦点 JComboBox 的突出显示颜色

如何在文本区域(坐标)角度中获取位置突出显示的文本?

如果关闭弹出窗口,QComboBox将保留鼠标悬停突出显示

如何在 Eclipse 的代码辅助弹出窗口中更改当前选定行的颜色?

显示从 parse.com 获取的解析通知作为弹出窗口