12.9.4 使用ListCellRenderer改变列表项外观
前面程序中的JList
和JComboBox
采用的都是简单的字符串列表项,实际上,JList
和JComboBox
还可以支持图标列表项,如果在创建JList
或JComboBox
时传入图标数组,则创建的JList
和JCombobox
的列表项就是图标。
如果希望列表项是更复杂的组件,例如,希望像QQ
程序那样每个列表项既有图标,也有字符串,那么可以通过调用JList
的setCellRenderer
方法来实现,该方法需要接收一个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
组件,该组件就代表了JList
或JComboBox
的每个列表项
自定义绘制JList
和JComboBox
的列表项所用的方法相同,所用的列表项绘制器也相同,故本节以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[] { "李清照", "苏格拉底", "李白", "弄玉", "虎头" }; private JList<String> friendsList = new JList<>(friends); public void init() { 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(); return this; } 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 ); } public Dimension getPreferredSize() { return new Dimension(60, 80); } }
|
上面程序中指定了该JList
对象使用ImageCellRenderer
作为列表项绘制器,ImageCellRenderer
重写了paintComponent()
方法来绘制单元格内容。除此之外,ImageCellRenderer
还重写了getPreferredSize()
方法,该方法返回一个Dimension
对象,用于描述该列表项绘制器的最佳大小。
运行上面程序,会看到如图12.37所示的窗口。
定义列表项绘制器有什么用
通过使用自定义的列表项绘制器,可以让JList
和JComboBox
的列表项是任意组件,并且可以在该组件上任意添加内容。