The preceding example displays items as strings in a list. JList is very flexible and versatile, and it can be used to display images and GUI components in addition to simple text. This section introduces list cell renderers for displaying graphics.
In addition to delegating data storage and processing to list models, JList delegates the rendering of list cells to list cell renderers. All list cell renderers implement the ListCellRenderer interface, which defines a single method, getListCellRendererComponent , as follows :
public Component getListCellRendererComponent (JList list, Object value, int index, boolean isSelected, boolean cellHasFocus)
This method is passed with a list, the value associated with the cell, the index of the value, and information regarding whether the value is selected and whether the cell has the focus. The component returned from the method is painted on the cell in the list. By default, JList uses DefaultListCellRenderer to render its cells. The DefaultListCellRenderer class implements ListCellRenderer , extends JLabel , and can display either a string or an icon, but not both in the same cell.
For example, you can use JList 's default cell renderer to display strings, as shown in Figure 30.22(a), using the following code:
JList list = new JList( new String[]{ "Denmark" , " Germany " , "China" , "India" , "Norway" , "UK" , "US" });
You can use JList 's default cell renderer to display icons, as shown in Figure 30.22(b), using the following code:
ImageIcon denmarkIcon = new ImageIcon(getClass().getResource( "image/denmarkIcon.gif" )); ... JList list = new JList( new ImageIcon[]{denmarkIcon, germanyIcon, chinaIcon, indiaIcon, norwayIcon, ukIcon, usIcon});
How do you display a string along with an icon in one cell, as shown in Figure 30.22(c)? You need to create a custom renderer by implementing ListCellRenderer , as shown in Figure 30.23.
Suppose a list is created as follows:
JList list = new JList( new Object[][]{{denmarkIcon, "Denmark" }, {germanyIcon, "Germany" }, {chinaIcon, "China" }, {indiaIcon, "India" }, {norwayIcon, "Norway" }, {ukIcon, "UK" }, {usIcon, "US" }});
Each item in the list is an array that consists of an icon and a string. You can create a custom cell renderer that retrieves an icon and a string from the list data model and displays them in a label. The custom cell renderer class is given in Listing 30.9.
1 import java.awt.*; 2 import javax.swing.*; 3 import javax.swing.border.*; 4 5 public class MyListCellRenderer implements ListCellRenderer { 6 private JLabel jlblCell = new JLabel( " " , JLabel.LEFT); 7 private Border lineBorder = 8 BorderFactory.createLineBorder(Color.black, 1 ); 9 private Border emptyBorder = 10 BorderFactory.createEmptyBorder( 2 , 2 , 2 , 2 ); 11 12 /** Implement this method in ListCellRenderer */ 13 public Component getListCellRendererComponent 14 (JList list, Object value, int index, boolean isSelected, 15 boolean cellHasFocus) { 16 Object[] pair = (Object[])value; // Cast value into an array 17 jlblCell.setOpaque( true ); 18 jlblCell.setIcon((ImageIcon)pair[ ]); 19 jlblCell.setText(pair[ 1 ].toString()); 20 21 if (isSelected) { 22 jlblCell.setForeground(list.getSelectionForeground()); 23 jlblCell.setBackground(list.getSelectionBackground()); 24 } 25 else { 26 jlblCell.setForeground(list.getForeground()); 27 jlblCell.setBackground(list.getBackground()); 28 } 29 30 jlblCell.setBorder(cellHasFocus ? lineBorder : emptyBorder); 31 32 return jlblCell; 33 } 34 } |
The MyListCellRenderer class implements the getListCellRendererComponent method in the ListCellRenderer interface. This method is passed with the parameters list , value , index , isSelected , and isFocused (lines 13 “15). The value represents the current item value. In this case, it is an array consisting of two elements. The first element is an image icon (line 18). The second element is a string (line 19). Both image icon and string are displayed on a label. The getListCellRendererComponent method returns the label (line 32), which is painted on the cell in the list.
If the cell is selected, the background and foreground of the cell are set to the list's selection background and foreground (lines 22 “23). If the cell is focused, the cell's border is set to the line border (line 30); otherwise , it is set to the empty border (line 39). The empty border serves as a divider between the cells.
Note
The example in Listing 30.9 uses a JLabel as a renderer. You may use any GUI component as a renderer, returned from the getListCellRendererComponent method. |
Let us develop an example that creates a list of countries and displays the flag image and name for each country as one item in the list, as shown in Figure 30.24. When a country is selected in the list, its flag is displayed in a label next to the list.
Two types of icons are used in this program. The small icons are created from files flagIcon0.gif , ..., flagIcon6.gif (lines 31 “32). The small icons are rendered inside the list. The large icons are created from files flag0.gif , ..., flag6.gif (lines 35 “36) and are displayed on a label on the right side of the split pane. Listing 30.10 gives the program.
1 import javax.swing.*; 2 import javax.swing.event.*; 3 import java.awt.*; 4 5 public class ListCellRendererDemo extends JApplet { 6 private final static int NUMBER_OF_NATIONS = 7 ; 7 private String[] nations = new String[] 8 { "Denmark" , "Germany" , "China" , "India" , "Norway" , "UK" , "US" }; 9 private ImageIcon[] icons = new ImageIcon[NUMBER_OF_NATIONS]; 10 private ImageIcon[] bigIcons = new ImageIcon[NUMBER_OF_NATIONS]; 11 12 // Create a list model 13 private DefaultListModel listModel = new DefaultListModel(); 14 15 // Create a list using the list model 16 private JList jlstNations = new JList(listModel); 17 18 // Create a list cell renderer 19 private ListCellRenderer renderer = new MyListCellRenderer(); 20 21 // Create a split pane 22 private JSplitPane jSplitPane1 = new JSplitPane(); 23 24 // Create a label for displaying image 25 private JLabel jlblImage = new JLabel( "" , JLabel.CENTER); 26 27 /** Construct ListCellRenderer */ 28 public ListCellRendererDemo() { 29 // Load small and large image icons 30 for ( int i = ; i < NUMBER_OF_NATIONS; i++) { 31 icons[i] = new ImageIcon(getClass().getResource( 32 "image/flagIcon" + i + ".gif" )); 33 listModel.addElement( new Object[]{icons[i], nations[i]}); 34 35 bigIcons[i] = new ImageIcon(getClass().getResource( 36 "image/flag" + i + ".gif" )); 37 } 38 39 // Set list cell renderer 40 jlstNations.setCellRenderer(renderer); 41 jlstNations.setPreferredSize( new Dimension( 200 , 200 )); 42 jSplitPane1.setLeftComponent( new JScrollPane(jlstNations)); 43 jSplitPane1.setRightComponent(jlblImage); 44 jlstNations.setSelectedIndex( ); 45 jlblImage.setIcon(bigIcons[ ]); 46 add(jSplitPane1, BorderLayout.CENTER); 47 48 // Register listener 49 jlstNations.addListSelectionListener( new ListSelectionListener() { 50 public void valueChanged(ListSelectionEvent e) { 51 jlblImage.setIcon(bigIcons[jlstNations.getSelectedIndex()]); 52 } 53 }); 54 } 55 } |
Two types of icons are used in this program. The small icons are created from files flagIcon0.gif , ..., flagIcon6.gif (lines 31 “32). These image files are the flags for Denmark, Germany, China, India, Norway, UK, and US. The small icons are rendered inside the list. The large icons for the same countries are created from files flag0.gif , ..., flag6.gif (lines 35 “36) and are displayed on a label on the right side of the split pane.
The ListCellRendererDemo class creates a list model (line 13) and adds the items to the model (line 33). Each item is an array of two elements (image icon and string). The list is created using the list model (line 16). The list cell renderer is created (line 19) and associated with the list (line 40).
The ListCellRendererDemo class creates a split pane (line 22) and places the list on the left (line 42) and a label on the right (line 43).
When you choose a country in the list, the list-selection event handler is invoked (lines 49 “53) to set a new image to the label in the right side of the split pane (line 51).