Posted on 2010-08-23 13:56
TWaver 阅读(2032)
评论(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变化时发送事件。
好了,由于代码和原理都比较简单,不再赘述,直接给出代码,以及简单注释。
1
import java.awt.*;
2
import java.awt.event.*;
3
import javax.swing.*;
4
import javax.swing.event.*;
5
6
public 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(300, 300, 400, 200);
196
frame.setVisible(true);
197
}
198
}
运行效果如下图:
