TWaver - 专注UI技术

http://twaver.servasoft.com/
posts - 171, comments - 191, trackbacks - 0, articles - 2
  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

Swing探秘:编写一个JCheckListBox组件

Posted on 2010-08-23 13:56 TWaver 阅读(2031) 评论(1)  编辑  收藏

记得Delphi里面有一个TCheckListBox控件,是一个可打勾的列表。但是这个东西在Swing里面并没有现成的。如今,我们就一起动手制作一个。根据Java的管理,就叫JCheckListBox吧。

写代码之前,先考虑以下问题:

  • 继承:当然是从Swing的JList继承。
  • 数据扩充:对于JList来说,它是显示了一系列Object。无论其类型如何,都用一个默认的渲染器(DefaultListCellRenderer,从JLabel继承而来)来画,每个条目的文字用Object.toString()来设置。但是对于JCheckListBox来说,除了显示文本外,还要考虑每个条目是否被选中,如果选中,要显示“打勾”。所以,JList需要维护“每一个条目是否选中”的状态信息。我们放在一个boolean数组中。
  • 渲染器:默认的Renderer肯定是不行了,无法显示打勾。自然想到用JCheckBox来重新做一个渲染器,设置到JCheckListBox中。
  • 鼠标监听器:现在可以画每个条目了,但还不够,必须能响应鼠标的点击以便Check/UnCheck才行。所以要在JCheckListBox上加一个鼠标监听器来响应鼠标事件。当然,如果你想让它相应键盘输入(例如Ctrl+A全选)也可如法炮制。
  • CheckListBoxModel:为了操作方便,这里还从AbstractListModel扩充一个CheckListBoxModel,它能在条目Check变化时发送事件。

好了,由于代码和原理都比较简单,不再赘述,直接给出代码,以及简单注释。

  1import java.awt.*;
  2import java.awt.event.*;
  3import javax.swing.*;
  4import javax.swing.event.*;
  5
  6public class JCheckListBox extends JList {
  7    //这个boolean数组装载所有item是否被check的信息。
  8
  9    private boolean[] checkedItems = null;
 10
 11    /**
 12     * 定义一个简单的ListModel,它可以发送check变化事件。
 13     */

 14    class CheckListBoxModel extends AbstractListModel {
 15
 16        private Object[] items = null;
 17
 18        CheckListBoxModel(Object[] items) {
 19            this.items = items;
 20        }

 21
 22        public int getSize() {
 23            return items.length;
 24        }

 25
 26        public Object getElementAt(int i) {
 27            return items[i];
 28        }

 29
 30        protected void fireCheckChanged(Object source, int index) {
 31            fireContentsChanged(source, index, index);
 32        }

 33
 34        public Object getItem(int index) {
 35            return items[index];
 36        }

 37    }

 38
 39    /**
 40     * 这里就覆盖了一个构造函数。其他JList你自己覆盖吧,反正super一下再init就OK了。
 41     * @param items Object[]
 42     */

 43    public JCheckListBox(Object[] items) {
 44        setModel(new CheckListBoxModel(items));
 45        init();
 46    }

 47
 48    /**
 49     * 初始化控件。包括初始化boolean数组、安装一个渲染器、安装一个鼠标监听器。
 50     */

 51    protected void init() {
 52        checkedItems = new boolean[this.getModel().getSize()];
 53        class MyCellRenderer extends JCheckBox implements ListCellRenderer {
 54
 55            public MyCellRenderer() {
 56                setOpaque(true);
 57            }

 58
 59            public Component getListCellRendererComponent(
 60                    JList list,
 61                    Object value,
 62                    int index,
 63                    boolean isSelected,
 64                    boolean cellHasFocus) {
 65                //这点代码基本上从DefaultListCellRenderer.java中抄袭的。
 66                setComponentOrientation(list.getComponentOrientation());
 67                if (isSelected) {
 68                    setBackground(list.getSelectionBackground());
 69                    setForeground(list.getSelectionForeground());
 70                }
 else {
 71                    setBackground(list.getBackground());
 72                    setForeground(list.getForeground());
 73                }

 74
 75                if (value instanceof Icon) {
 76                    setIcon((Icon) value);
 77                    setText("");
 78                }
 else {
 79                    setIcon(null);
 80                    setText((value == null? "" : value.toString());
 81                }

 82                setEnabled(list.isEnabled());
 83                setFont(list.getFont());
 84
 85                //虽然抄袭,可这里别忘了设置check信息。
 86                this.setSelected(isChecked(index));
 87                return this;
 88            }

 89        }

 90
 91        this.setCellRenderer(new MyCellRenderer());
 92        //定义一个鼠标监听器。如果点击某个item,翻转其check状态。
 93        class CheckBoxListener extends MouseAdapter {
 94
 95            @Override
 96            public void mouseClicked(MouseEvent e) {
 97                int index = locationToIndex(e.getPoint());
 98                invertChecked(index);
 99            }

100        }

101
102        this.addMouseListener(new CheckBoxListener());
103    }

104
105    /**
106     * 翻转指定item的check状态。
107     * @param index int
108     */

109    public void invertChecked(int index) {
110        checkedItems[index] = !checkedItems[index];
111        //别忘了发送event。
112        CheckListBoxModel model = (CheckListBoxModel) getModel();
113        model.fireCheckChanged(this, index);
114        this.repaint();
115    }

116
117    /**
118     * 是否指定item被check。
119     * @param index int
120     * @return boolean
121     */

122    public boolean isChecked(int index) {
123        return checkedItems[index];
124    }

125
126    /**
127     * 获得选中的item个数
128     */

129    public int getCheckedCount() {
130        int result = 0;
131        for (int i = 0; i < checkedItems.length; i++{
132            if (checkedItems[i]) {
133                result++;
134            }

135        }

136        return result;
137    }

138
139    /**
140     * 所有选中item索引的数组。
141     */

142    public int[] getCheckedIndices() {
143        int[] result = new int[getCheckedCount()];
144        int index = 0;
145        for (int i = 0; i < checkedItems.length; i++{
146            if (checkedItems[i]) {
147                result[index] = i;
148                index++;
149            }

150        }

151        return result;
152    }

153
154    public static void main(String[] args) throws Exception {
155
156        Font font = new Font("微软雅黑", Font.PLAIN, 12);
157
158        JFrame frame = new JFrame("TWaver中文社区之Swing探秘");
159
160        final JCheckListBox list = new JCheckListBox(new Object[]{"张三""李四""王二麻子""木头六","小七子"});
161        list.setFont(font);
162        frame.getContentPane().add(new JScrollPane(list), BorderLayout.CENTER);
163        JButton button = new JButton("OK");
164        button.addActionListener(new ActionListener() {
165
166            public void actionPerformed(ActionEvent e) {
167                System.exit(0);
168            }

169        }
);
170        frame.getContentPane().add(button, BorderLayout.SOUTH);
171        final JLabel label = new JLabel("当前没有选择。");
172        label.setFont(font);
173        list.getModel().addListDataListener(new ListDataListener() {
174
175            public void intervalAdded(ListDataEvent e) {
176            }

177
178            public void intervalRemoved(ListDataEvent e) {
179            }

180
181            public void contentsChanged(ListDataEvent e) {
182                if (list.getCheckedCount() == 0{
183                    label.setText("当前没有选择。");
184                }
 else {
185                    String text = "当前选择:";
186                    int[] indices = list.getCheckedIndices();
187                    for (int i = 0; i < indices.length; i++{
188                        text += ((CheckListBoxModel) list.getModel()).getItem(indices[i]).toString() + ",";
189                    }

190                    label.setText(text);
191                }

192            }

193        }
);
194        frame.getContentPane().add(label, BorderLayout.NORTH);
195        frame.setBounds(300300400200);
196        frame.setVisible(true);
197    }

198}

运行效果如下图:


评论

# re: Swing探秘:编写一个JCheckListBox组件  回复  更多评论   

2010-08-24 09:25 by zeyuphoenix
恩 以前我也写过一个
http://www.blogjava.net/zeyuphoenix/archive/2010/05/03/319976.html
jlist是比较简单的组件,基本不用考虑ui的问题,比jtable和jtree好处理,也没什么高级扩展

只有注册用户登录后才能发表评论。


网站导航: