5

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

我正在尝试创建一个组件,该组件由一个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()));
                    }
                }
            });
        }
    }

}

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

4

2 回答 2

4

好问题和好解决方案 - 除了accessibleCombo 中似乎存在错误,它不会在updateUI 上更新其内部接线,也就是说,在切换LAF 时:

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

您对此无能为力。所以我会直接听列表选择,然后你可以完全控制 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();

    }
}
于 2013-04-10T15:41:50.083 回答
3

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

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

JTable 教程中的为单元格指定工具提示部分展示了如何对表格执行此操作。组合框渲染器的概念应该相同。

于 2013-04-10T15:36:55.273 回答