JList和JCombobox組件從本質上說是類似的,它們都是提供了一系列列表數據供用戶選擇,從表現(xiàn)形式上可以把JCombobox看做一個JList和一個JTextField組成,通過callback機制回調選擇項目.JList并沒有復雜的UI,當然也就沒有復雜的畫面了,所以對于提高JList的畫面表現(xiàn),一般繼承ListCellRenderer加入自己的表現(xiàn)樣式就可以了,當然依照Swing的MVC原則,需要修改數據時,實現(xiàn)ListModel接口就可以了,對選擇樣式修改,實現(xiàn)ListSelectionModel接口就可以了,它們的實現(xiàn)都相對簡單,功能也相對簡單,一般都不需要實現(xiàn),對于復雜畫面樣式也不推薦JList,單列的JTable和自己實現(xiàn)的JTree比它好很多.
JList的基本使用很簡單,先看Sun官方的使用例子:
界面如下:
只需要新創(chuàng)建一個DefaultListModel,賦予需要顯示的值就可以了.
DefaultListModel listModel = new DefaultListModel();
listModel.addElement("Debbie Scott");
listModel.addElement("Scott Hommel");
listModel.addElement("Sharon Zakhour");
然后創(chuàng)建JList:
JList list = new JList(listModel);
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
當然可以給它加監(jiān)聽:
list.addListSelectionListener(this);
也可以加鼠標的Click監(jiān)聽,這是所有JComponent都具有的能力.
然后實現(xiàn)監(jiān)聽就可以了:
// This method is required by
ListSelectionListener.
publicvoid valueChanged(ListSelectionEvent e) {
if
(e.getValueIsAdjusting() == false) {
最后把創(chuàng)建JList放入畫面上,就完成了.
Sun官方還給了一個使用JList的例子,在同一行顯示多個項目:
界面如下:
創(chuàng)建JList的過程和前一個例子相同,只是需要繼承JList把它的getScrollableUnitIncrement方法重寫,變成我們自己的表現(xiàn)樣式:
/**
* Returns the distance to scroll to expose
the next or previous
* row (for vertical scrolling) or column
(for horizontal scrolling).
*/
@Override
publicint getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
這個方法就是描繪JList前一個后一個行或者列的表現(xiàn)的,只需要根據容器的大小算出現(xiàn)在每個格子的大小:
Rectangle r = getCellBounds(row, row);
然后依次放置就可以了,布局使用FlowLayout.
Point loc = r.getLocation();
loc.y--;
int prevIndex = locationToIndex(loc);
Rectangle prevR =
getCellBounds(prevIndex, prevIndex);
if (prevR == null || prevR.y >= r.y) {
return 0;
}
return prevR.height;
當然也可以重寫其它的類實現(xiàn)其它樣式,復雜樣式也可以重寫JList的ListUI.
其它的JList的設置顏色,字體,背景等都很簡單,按照API就可以了,至于拖拽操作也和其它組件一樣.
最后我們實現(xiàn)一個自己的JList,在它的單元格內加入圖片,復選框,設置它是否可以選擇,圖片是否可以顯示,當然你也可以加入其它的表現(xiàn)形式,只需要再寫入新的接口.
界面如下:
當單元格是選中狀態(tài)時,點擊Print按鈕輸入選中的項目:
工程目錄如下:
先看幾個接口,
/**
* the interface that the JComboBox can Icon
enable.
*/
publicinterface IconEnable {
/**
* the interface that the list can have icon.
*/
publicinterface IconItem {
/**
* the interface that the JComboBox can select
enable.
*/
publicinterface SelectEnable {
/**
* the interface that the list can have select.
*/
publicinterface SelectItem {
它們都提供
/**
* set bean.
*/
publicvoid setXXX(XXX XXX);
/**
* get bean.
*/
public XXX getXXX();
來表示JList某項自定義屬性.
然后自定義一個類實現(xiàn)這些接口:
/**
* list item.
*/
publicclass MyListItem implements IconItem, IconEnable, SelectEnable,
SelectItem {
它的屬性:
/**
* list value.
*/
private Object listItem = null;
/**
* list is select.
*/
privatebooleanisSelected = false;
/**
* list icon.
*/
private Icon icon = null;
/**
* list icon enable.
*/
privatebooleanisIconEnable = true;
/**
* list is select enable.
*/
privatebooleanisSelectEnable = true;
這樣就使這個類可以保存JList的單元格的項,我們的JList的Model使用這個類的實例作為Bean來存儲JList的信息.
接著是一個JList項目的顯示描繪類,
/**
* the list cell's label.
*/
publicclass MyListLabel extends JLabel {
它復寫JLabel的
@Override
publicvoid
setBackground(Color color) {
@Override
publicvoid paint(Graphics g)
{
@Override
public Dimension
getPreferredSize() {
調整JList的單元格的顏色,圖片樣式,字體,焦點偏移和最適合大小.
g.setColor(UIManager.getColor("Tree.textBackground"));
g.drawRect(imageOffset, 0, d.width - 1 - imageOffset,
d.height - 1);
最后就是重要的畫面表現(xiàn)類MyListRenderer了,它需要實現(xiàn)ListCellRenderer接口
/**
* JList cell renderer.
*/
publicclass MyListRenderer extends JPanel implements
MouseListener,
ListCellRenderer {
通過繼承JPanel,使JList的單元格可以實現(xiàn)任何的控件效果,這里是放置一個JCheckBox和我們自定義的MyListLabel:
/**
* JList cell renderer.
*/
public MyListRenderer(JList list) {
this.list = list;
setLayout(null);
add(checkBox = new JCheckBox());
add(label = new MyListLabel());
checkBox.setBackground(UIManager.getColor("Tree.textBackground"));
label.setForeground(UIManager.getColor("Tree.textForeground"));
commonIcon = UIManager.getIcon("Tree.leafIcon");
}
實現(xiàn)接口的getListCellRendererComponent方法,返回我們需要的呈現(xiàn):
/**
* Return a component that
has been configured to display the specified
* value.
*/
@Override
public Component getListCellRendererComponent(JList list,
Object value, int index, boolean isSelected, boolean cellHasFocus) {
其中value就是我們的自定義單元格MyListItem,可以設置屬性:
設置可用:
setEnabled(((SelectEnable) value).isSelectEnabled());
設置選擇: checkBox.setSelected(((SelectItem)
value).getSelect());
設置Label的選擇: label.setSelected(isSelected);
設置字體和圖片:
label.setFont(list.getFont());
label.setText(value.toString());
label.setFocus(cellHasFocus);
if (((IconEnable) value).isIconEnabled()) {
Icon icon = ((IconItem) value).getIcon();
if (icon == null) {
icon = commonIcon;
}
label.setIcon(icon);
}
同樣也通過重寫getPreferredSize、setBackground和doLayout設置合適大小、顏色和布局:
Dimension d_check
= checkBox.getPreferredSize();
Dimension d_label = label.getPreferredSize();
returnnew Dimension(d_check.width + d_label.width,
(d_check.height < d_label.height ? d_label.height
: d_check.height));
通過兩個組件的合適大小可以得出兩個組件的位置:
y_check = (d_label.height - d_check.height) / 2;
然后通過設定位置,做出Layout:
label.setLocation(d_check.width, y_label);
label.setBounds(d_check.width, y_label, d_label.width, d_label.height);
最后處理的是JList的鼠標選擇JCheckBox事件,
@Override
publicvoid mouseClicked(MouseEvent e) {
通過選擇定位選擇的Item,然后對應設置選中狀態(tài),刷新:
int index = list.locationToIndex(e.getPoint());
MyListItem item = (MyListItem) list.getModel().getElementAt(index);
if (((SelectEnable) item).isSelectEnabled()) {
item.setSelect(!((SelectItem) item).getSelect());
Rectangle rect = list.getCellBounds(index, index);
ist.repaint(rect);
}
這個我們的JList就設置完了,它的使用和普通的一樣,只不過Model使用的是MyListItem數組:
MyListItem[]
items = { new MyListItem("Astart"),
new MyListItem("B-BIX", true, icon),
new MyListItem("have fun game!", false, null, false, false),
new MyListItem("郁悶", false),
new MyListItem("abc", true),
new MyListItem("12867831", false, icon),
new MyListItem("happy", false, null, false, true),
new MyListItem("defINE", false, null) };
JList jList = new JList(items);
設置Renderer:
jList.setCellRenderer(new MyListRenderer(jList));
然后得到的JList就和普通JComponent一樣使用了.