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

时间:2013-04-10 14:12:20

标签: java swing selection jcombobox highlight

我希望能够在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()));
                    }
                }
            });
        }
    }

}

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

2 个答案:

答案 0 :(得分:3)

  

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

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

JTable教程中的Specifying Tool Tips For Cells部分显示了如何为表执行此操作。对于comboBox渲染器,该概念应该相同。

答案 1 :(得分:2)

好的问题和良好的解决方案 - 除了似乎在accessibleCombo中没有更新其在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();

    }
}