JCombox作为容器构建复合组件

JCombox是JSwing中比较常用的组件,它显示的是一个项列表,扩展的是ListModil模型,利用ListCellBenderer来绘制下拉的每个Item。 同时Jcombox也可以作为一个容器, 将JLable, JCheckbox等做为Item显示在下拉项中,构成一个复合组件。下面以下拉选项中是JCheckBox选项(如下图所示)来分析如何构建JCombox的组合组件。

 
首先,JCombox是以ListCellBenderer接口来绘制下拉Item的,所以,Item由以前的String改成JComponent, 必须重新实现该接口,制作自己的Renderer。 ListCellRenderer接口就一个方法:getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {},
其中,各个参数的定义如下:
list: 正在绘制的JList, 比如下拉菜单
value: 选中的Item的值,可以是string, 也可以是自己写的一个Item,用list.getModel().getElementAt(index) 返回的值;
index: 选中的Item的索引,-1代表什么都不选择;
isSelected: 该单元格/Item是否被选中;
cellHasFocus: 该Item是否拥有焦点;
ListCellRenderer的工作原理: 在绘制JList的每个Cell之前,它会去调用getListCellRendererComponent( ),得到一个Component,并
将这个Component绘制在正确的位置.因为getListCellRendererComponent( )返回的是Component,所以我们几乎可以扩展任意一个Component,来改变JList,JComboBox等的外观(关于渲染器或者绘制器的原理和知识见如下文章:http://piscesky.iteye.com/blog/281996 http://www.java3z.com/cwbwebhome/article/pr/sw13.jsp)。
实现自己的Renderer,需要extends你要放在下拉菜单中的JComponent, 并且implements ListCellRenderer接口,然后return自己。代码如下:
 1 public class ComboCheckBoxRenderer extends JCheckBox implements ListCellRenderer, Serializable
 2     {
 3         private DefaultListCellRenderer labelRenderer;
 4 
 5         public ComboCheckBoxRenderer()
 6         {
 7             super();
 8             setOpaque(true);
 9             setBorder(noFocusBorder);
10         }
11 
12         public Component getListCellRendererComponent(
13                 JList list,
14                 Object value,
15                 int index,
16                 boolean isSelected,
17                 boolean cellHasFocus)
18         {
19             ComboCheckBoxEntry item = (ComboCheckBoxEntry) value;
20             if (item.key == KEY_TITLE)
21             {
22                 if (labelRenderer == null)
23                     labelRenderer = new DefaultListCellRenderer();
24                 return labelRenderer.getListCellRendererComponent(list, item.value, index, isSelected, cellHasFocus);
25             }
26 
27             setComponentOrientation(list.getComponentOrientation());
28             if (isSelected)
29             {
30                 setBackground(list.getSelectionBackground());
31                 setForeground(list.getSelectionForeground());
32             }
33             else
34             {
35                 setBackground(list.getBackground());
36                 setForeground(list.getForeground());
37             }
38 
39             setSelected(item.checked);
40             setText(item.value);
41             setEnabled(list.isEnabled());
42             if (isAllItemSelected() && item.key != KEY_ALL)
43                 setEnabled(false);
44             setFont(list.getFont());
45             setBorder((cellHasFocus) ? UIManager.getBorder("List.focusCellHighlightBorder") : noFocusBorder);
46             
47             return this;
48         }
49     }
 

 也可以加上提示为每个选项,比如39行改为如下,就可以实现当选择某个item时候,提示你已经选择该item。

if(item.checked){
  list.setToolTipText(item.value + "have been selected");
}
setSelected(item.checked);

其次, 定制符合特定的Item结构来满足你的下拉菜单的显示,代码如下:

public class ComboCheckBoxEntry
    {
        boolean checked;
        Object key;
        String value;

        public ComboCheckBoxEntry(boolean checked, Object key, String value)
        {
            this.checked = checked;
            this.key = key;
            this.value = value;
        }
        
        public String toString()
        {
            return value == null ? "" : value;
        }
    }

定制的Item结构也可以继承一些接口,来实现一些功能,比如实现SelectEnable接口,使得Item具有是否采用线的样式,其实不继承这个接口,直接在Item里面增加一个属性isLineEnabled也行:

public interface LineEnable {
    public void setLineEnabled(boolean isLineEnabled);
    public boolean isLineEnabled();
}


public class MyComboBoxItem implements SelectEnable, LineEnable {

/*对于特殊的JCombobox设置Item时,设置MyComboBoxItem就可以使Item具有选择可否和是否是线的样式.*/

    private Object comboxItem = null;
    boolean isLineEnabled = false;
}

最后,设置JCombox的UI来控制显示,代码如下:

public class ComboCheckBoxUI extends MetalComboBoxUI
    {
        protected ComboPopup createPopup()
        {
            ComboCheckPopUp comboCheckPopUp = new ComboCheckPopUp(comboBox);
            list = comboCheckPopUp.getList();
            return comboCheckPopUp;
        }

        public class ComboCheckPopUp extends BasicComboPopup
        {
            public ComboCheckPopUp(JComboBox cBox)
            {
                super(cBox);
            }

            @Override
            protected JList createList()
            {
                final ComboBoxModel model = comboBox.getModel();
                
                // wrapper model 屏蔽Title Item Entry
                final DefaultComboBoxModel wrapper = new DefaultComboBoxModel();
                model.addListDataListener(new ListDataListener()
                {
                    public void contentsChanged(ListDataEvent e)
                    {}
                    public void intervalAdded(ListDataEvent e)
                    {
                        ComboCheckBoxEntry item = (ComboCheckBoxEntry) model.getElementAt(e.getIndex0());
                        if (item.key != KEY_TITLE)
                            wrapper.addElement(item);
                    }
                    public void intervalRemoved(ListDataEvent e)
                    {
                        int index = e.getIndex0() - 1;
                        if (index >= 0 && index <= wrapper.getSize())
                            wrapper.removeElementAt(index);
                    }
                });

                return new JList(wrapper)
                {
                    public void processMouseEvent(MouseEvent e)
                    {
                        if (e.isControlDown())
                        {
                            e = new MouseEvent((Component) e.getSource(), e.getID(), e.getWhen(), e.getModifiers()
                                    ^ InputEvent.CTRL_MASK, e.getX(), e.getY(), e.getClickCount(), e.isPopupTrigger());
                        }
                        super.processMouseEvent(e);
                    }
                };
            }

            @Override
            protected int getPopupHeightForRowCount(int maxRowCount)
            {
                int minRowCount = Math.min(maxRowCount, list.getModel().getSize());
                int height = 0;
                ListCellRenderer renderer = list.getCellRenderer();
                Object value = null;

                for (int i = 0; i < minRowCount; ++i)
                {
                    value = list.getModel().getElementAt(i);
                    Component c = renderer.getListCellRendererComponent(list, value, i, false, false);
                    height += c.getPreferredSize().height;
                }

                return height == 0 ? 100 : height;
            }

            @Override
            protected MouseListener createListMouseListener()
            {
                return new CheckBoxListMouseHandler();
            }

            protected class CheckBoxListMouseHandler extends MouseAdapter
            {
                @Override
                public void mousePressed(MouseEvent anEvent)
                {
                    int index = list.getSelectedIndex();
                    ComboCheckBoxEntry item = (ComboCheckBoxEntry) list.getModel().getElementAt(index);
                    if (item == null)
                        return;
                    if (item.key == KEY_TITLE)
                        return;
                    if (isAllItemSelected() && item.key != KEY_ALL)
                        return;
                    if (item.key == KEY_ALL && item.checked == false)
                    {
                        ListModel mdl = list.getModel();
                        for (int i = 0; i < mdl.getSize(); i++)
                        {
                            ComboCheckBoxEntry entry = (ComboCheckBoxEntry) mdl.getElementAt(i);
                            if (entry.key == KEY_ALL || entry.key == KEY_TITLE)
                                continue;
                            entry.checked = false;
                        }
                    }

                    boolean checked = !item.checked;
                    int size = list.getModel().getSize();
                    item.checked = checked;
                    updateListBoxSelectionForEvent(anEvent, false);
                    fireItemStateChanged(new ItemEvent(MultiSelectionComboBox.this, 0, null, 0));
                    Rectangle rect = list.getCellBounds(0, size - 1);
                    list.repaint(rect);
                }
            }
        }
    }

现在测试如下:

 1 public class TestJcombox {
 2 
 3     /**
 4      * @param args
 5      */
 6     public static void main(String[] args) {
 7         // TODO Auto-generated method stub
 8 
 9         JDialog jDialog = new JDialog();
10         jDialog.setLayout(new FlowLayout());
11         MultiSelectionComboBox multiSel = new MultiSelectionComboBox("", true);
12         multiSel.addItem(1, "中国");
13         multiSel.addItem(2, "印度");
14         multiSel.addItem(3, "日本");
15         jDialog.add(multiSel);
16         jDialog.setSize(200, 300);
17         jDialog.setVisible(true);
18     }
19 
20 }

就可以得到开篇图所说的效果。

 引文:

http://www.cnblogs.com/zhangxz/archive/2012/10/11/2720241.html

http://www.blogjava.net/zeyuphoenix/archive/2010/04/12/318014.html

http://www.java3z.com/cwbwebhome/article/pr/sw13.jsp

http://piscesky.iteye.com/blog/281996

http://blog.csdn.net/tyro668/article/details/4246347

http://blog.csdn.net/heruiup/article/details/5995697

原文地址:https://www.cnblogs.com/kangls/p/2972943.html