12.9.4 使用ListCellRenderer改变列表项外观

12.9.4 使用ListCellRenderer改变列表项外观

前面程序中的JListJComboBox采用的都是简单的字符串列表项,实际上,JListJComboBox还可以支持图标列表项,如果在创建JListJComboBox时传入图标数组,则创建的JListJCombobox的列表项就是图标。
如果希望列表项是更复杂的组件,例如,希望像QQ程序那样每个列表项既有图标,也有字符串,那么可以通过调用JListsetCellRenderer方法来实现,该方法需要接收一个ListCellRenderer对象,该对象代表一个列表项绘制器

方法 描述
void setCellRenderer(ListCellRenderer<? super E> cellRenderer) Sets the delegate that is used to paint each cell in the list.

ListCellRenderer接口

ListCellRenderer是一个接口,该接口里包含一个方法:

方法 描述
Component getListCellRendererComponent(JList<? extends E> list, E value, int index, boolean isSelected, boolean cellHasFocus) Return a component that has been configured to display the specified value.

上面的getListCellRendererComponent()方法返回一个Component组件,该组件就代表了JListJComboBox的每个列表项

自定义绘制JListJComboBox的列表项所用的方法相同,所用的列表项绘制器也相同,故本节以JList为例

ListCellRenderer只是一个接口,它并未强制指定列表项绘制器属于哪种组件,因此可扩展任何组件来实现ListCellRenderer接口。通常采用扩展其他容器(如JPanel)的方式来实现列表项绘制器,实现列表项绘制器时可通过重写paintComponent()的方法来改变单元格的外观行为。

程序 列表项绘制器

例如下面程序,重写paintComponent方法时先绘制好友图像,再绘制好友名字。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
import java.awt.*;
import javax.swing.*;

public class ListRenderingTest
{
private JFrame mainWin = new JFrame("好友列表");
private String[] friends = new String[]
{
"李清照",
"苏格拉底",
"李白",
"弄玉",
"虎头"
};
// 定义一个JList对象
private JList<String> friendsList = new JList<>(friends);
public void init()
{
// 设置该JList使用ImageCellRenderer作为列表项绘制器
friendsList.setCellRenderer(new ImageCellRenderer());
mainWin.add(new JScrollPane(friendsList));
mainWin.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainWin.pack();
mainWin.setVisible(true);
}
public static void main(String[] args)
{
new ListRenderingTest().init();
}
}
class ImageCellRenderer extends JPanel
implements ListCellRenderer<String>
{
private ImageIcon icon;
private String name;
// 定义绘制单元格时的背景色
private Color background;
// 定义绘制单元格时的前景色
private Color foreground;
public Component getListCellRendererComponent(JList list
, String value , int index
, boolean isSelected , boolean cellHasFocus)
{
icon = new ImageIcon("ico/" + value + ".gif");
name = value;
background = isSelected ? list.getSelectionBackground()
: list.getBackground();
foreground = isSelected ? list.getSelectionForeground()
: list.getForeground();
// 返回该JPanel对象作为列表项绘制器
return this;
}
// 重写paintComponent方法,改变JPanel的外观
public void paintComponent(Graphics g)
{
int imageWidth = icon.getImage().getWidth(null);
int imageHeight = icon.getImage().getHeight(null);
g.setColor(background);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(foreground);
// 绘制好友图标
g.drawImage(icon.getImage() , getWidth() / 2
- imageWidth / 2 , 10 , null);
g.setFont(new Font("SansSerif" , Font.BOLD , 18));
// 绘制好友用户名
g.drawString(name, getWidth() / 2
- name.length() * 10 , imageHeight + 30 );
}
// 通过该方法来设置该ImageCellRenderer的最佳大小
public Dimension getPreferredSize()
{
return new Dimension(60, 80);
}
}

上面程序中指定了该JList对象使用ImageCellRenderer作为列表项绘制器,ImageCellRenderer重写了paintComponent()方法来绘制单元格内容。除此之外,ImageCellRenderer还重写了getPreferredSize()方法,该方法返回一个Dimension对象,用于描述该列表项绘制器的最佳大小。
运行上面程序,会看到如图12.37所示的窗口。

定义列表项绘制器有什么用

通过使用自定义的列表项绘制器,可以让JListJComboBox的列表项是任意组件,并且可以在该组件上任意添加内容