Swing ListCellRenderer的功能

时间:2013-07-26 12:33:04

标签: java swing jlist listcellrenderer

关于JavaDoc for javax.swing.ListCellRenderer中的示例代码的简短问题:

我有点惊讶,在示例中,ListCellRenderer由扩展JLabel的类实现,而getListCellRendererComponent(...) - 方法只返回this 。看起来当时只有JLabel的一个实例,即使对于包含多个元素的列表也是如此。

通常,我会期望当setText(...)方法在getListCellRendererComponent(...)内为列表中的第二项调用时,它会更改列表中已存在的第一项的标签。或者,实际上,列表可能甚至不可能对列表中的每个项目使用相同的JLabel - 实例两次(或更多次)。

现在,我已经提出了两种可能的方法来解决这个问题,并且想知道哪一个(如果有的话)实际发生了:

  • JList是否以某种方式为每个列表项创建了提供的ListCellRenderer的新实例?
  • 或者它是否仅使用getListCellRendererComponent(...)返回的组件来调用列表画布上的paint(...)方法,而不是实际将此组件添加到某个面板?

1 个答案:

答案 0 :(得分:3)

JList渲染时,它会向ListModel询问它应显示的元素。 对于每个元素,它调用javax.swing.ListCellRenderer来提供渲染组件。然后它绘制组件。就这样。渲染组件未绑定到它呈现的元素状态。

ListCellRenderer的javadoc说:

  

识别可用作“橡皮图章”的组件       在JList中绘制单元格。

所以你的第二个假设是正确的。

javax.swing.plaf.BasicListUI看一看:

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);
}