扩展DefaultTableCellRenderer,getTableCellRendererComponent中没有创建新对象?

min*_*ins 0 java swing jtable tablecellrenderer

我在理解单元格渲染器时遇到一些困难。StretchIcon我想在 a 中使用JTable,以便列的单元格显示调整大小的徽标。StretchIcon延伸ImageIcon

自定义渲染器:

public class IconCellRenderer extends DefaultTableCellRenderer {

    @Override
    public Component getTableCellRendererComponent(JTable table, Object value,
            boolean isSelected, boolean hasFocus, int row, int column) {

        JLabel label = new JLabel();
        label.setIcon( (Icon) ( new StretchIcon((Image) value) ) );

        return label;
    }
}
Run Code Online (Sandbox Code Playgroud)

该代码按预期工作,我对表格没有任何问题。

从本教程中,我了解到出于getTableCellRendererComponent性能原因,我应该避免创建新对象。

我不明白:

  • 将被实例化多少次IconCellRenderer。我假设只有一次,在JTable创建时(假设表中只有一列)。

  • getTableCellRendererComponent会被调用多少次。我假设列中的每个单元格都调用一次,以便它可以为每个单元格返回一个JLabel带有嵌入实例的新实例StretchIconStretchIcon如果这是真的,那么在方法中 创建 JLabel 和 的新实例就有意义了。

  • 需要时如何重新绘制调整大小的图标(隐藏单元格然后再次显示,或调整单元格大小)?我假设getTableCellRendererComponent根本不参与此操作,并且这完全是使用paintJLabel 的方法paintStretchIcon.

我的理解有些不正确吗?StretchIcon在方法中创建新实例是否合法?我可以做什么来优化这个单元格渲染器,例如我可以使标签对象静态吗?


编辑:根据提供的评论和答案,我最终得到了这个单元格渲染器:

public class StretchIconRenderer extends DefaultTableCellRenderer {

    private static StretchIcon stretched;

    @Override
    public Component getTableCellRendererComponent(JTable table, Object value,
            boolean isSelected, boolean hasFocus, int row, int column) {

        super.getTableCellRendererComponent(table, value, 
                isSelected, hasFocus, row, column);

        Image logo = (Image) value;

        if (stretched == null) { stretched = new StretchIcon(logo); }
        else { stretched.setImage(logo); }

        setIcon(stretched);
        setText(null);

        return this;
    }
}
Run Code Online (Sandbox Code Playgroud)

Mad*_*mer 5

将被实例化多少次IconCellRenderer。我假设只有一次,在创建 JTable 时(假设表中只有一列)。

从技术上讲,它只需要创建一次,但可以根据需要多次创建。然而,一旦分配给JTable/ TableColumn,这些类将永远不会再次启动它。他们只是维护对您传递给他们的实例的引用

getTableCellRendererComponent会被调用多少次。我假设列中的每个单元格都调用一次,这样它就可以返回一个新的 JLabel 实例,并StretchIcon为每个单元格嵌入一个 的实例。如果这是真的,那么在方法中创建JLabel和的新实例就有意义了。StretchIcon

是的,这是真的,getTableCellRendererComponent将为表中的每一行调用。但是,您不需要创建组件的新实例,您可以返回为每行配置不同的相同实例。

原因是,表格简单地将结果“绘制”到其自身上,它不会以您习惯的方式“添加”组件。这通常被称为“饼干切割机”或“橡皮印章”,因为该组件仅用作模板。

需要时如何重新绘制调整大小的图标(隐藏单元格然后再次显示,或调整单元格大小)?我假设getTableCellRendererComponent根本不参与此操作,并且这完全是使用 的 Paint 方法JLabel以及 中重新定义的 Paint 方法完成的StretchIcon

不,这完全是通过getTableCellRendererComponent. TableModel当单元格/行/列以某种方式更新时,必须从或触发通知ColumnModel,指示表已发生更改。

该表将确定受影响的单元格并使用适当的方法重新绘制它们TableCellRenderer

简而言之。应该不需要创建JLabelinside的新实例getTableCellRendererComponent。事实上,您甚至根本不需要它JLabel,因为DefaultTableCellRenderer它是从JLabel并且您应该简单地使用它。

我不知道如何StretchIcon工作,所以您可能别无选择,只能创建一个新实例,但如果可以的话,您可能会考虑创建一个WeakHashMap键控到该Object值,它维护 的引用StretchIcon,因此您只创建一个实例每行的...

例如...

public Component getTableCellRendererComponent(JTable table, Object value,
        boolean isSelected, boolean hasFocus, int row, int column) {

    super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
    setIcon(getStretchIconFor(value));

    return this;
}

protected StreatchIcon(Object value) {
    StretchIcon icon = null;
    if (!cache.contains(value)) {
        icon = new StretchIcon((Image) value) );
        cache.put(value, icon);
    }
    return icon;
}
Run Code Online (Sandbox Code Playgroud)

哪里cache有一个WeakHashMap...

阅读《概念:编辑器和渲染器》可能值得