Question

A quick question about the example code in the JavaDoc for javax.swing.ListCellRenderer:

I'm a little surprised, that in the example, the ListCellRenderer is implemented by a class that extends JLabel and that the getListCellRendererComponent(...)-method simply returns this. It looks like there is only one instance of a JLabel around then, even for a list containing more than one element.

Usually, I would then expect that when the setText(...) method is called inside getListCellRendererComponent(...) for the second item in the list, it changes the label of the already existing first item in the list. Or, actually, it probably shouldn't even be possible for the list to use the same JLabel-instance twice (or more times), once for each item in the list.

Now, I've come up with two possible ways to resolve this and was wondering which one (if any) is actually happening:

  • Does JList somehow create new instances of the provided ListCellRenderer for each list item?
  • Or does it use the component returned by getListCellRendererComponent(...) only to invoke its paint(...) method on the list's canvas rather than actually adding this component to some panel?
Was it helpful?

Solution

When the JList renders itself it asks the ListModel for the elements it should display. For each element it calls the javax.swing.ListCellRenderer to provide a render component. Then it paints the component. That's all. A render component is not bound to an element's state that it renders.

The javadoc of ListCellRenderer says:

Identifies components that can be used as "rubber stamps" to paint the cells in a JList.

So your second assumption is right.

A look at javax.swing.plaf.BasicListUI shows it:

protected void paintCell(Graphics g, int row, Rectangle rowBounds,
        ListCellRenderer cellRenderer, ListModel dataModel,
        ListSelectionModel selModel, int leadIndex) {
    Object value = dataModel.getElementAt(row);
    boolean cellHasFocus = list.hasFocus() && (row == leadIndex);
    boolean isSelected = selModel.isSelectedIndex(row);

    Component rendererComponent = cellRenderer
            .getListCellRendererComponent(list, value, row, isSelected,
                    cellHasFocus);

    int cx = rowBounds.x;
    int cy = rowBounds.y;
    int cw = rowBounds.width;
    int ch = rowBounds.height;

    if (isFileList) {
        // Shrink renderer to preferred size. This is mostly used on Windows
        // where selection is only shown around the file name, instead of
        // across the whole list cell.
        int w = Math
                .min(cw, rendererComponent.getPreferredSize().width + 4);
        if (!isLeftToRight) {
            cx += (cw - w);
        }
        cw = w;
    }

    rendererPane.paintComponent(g, rendererComponent, list, cx, cy, cw, ch,
            true);
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top