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

时间:2014-09-24 06:58:56

标签: java swing jtable tablecellrenderer

我很难理解细胞渲染器。我想在JTable中使用StretchIcon,以便列的单元格显示已调整大小的徽标。 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;
    }
}

此代码可以正常工作,我对该表没有任何问题。

从这个tutorial,我了解到我应该避免在getTableCellRendererComponent中出于性能原因而创建新对象。

我不明白:

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

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

  • 如何在需要时重新绘制已调整大小的图标(隐藏单元格然后再次显示,或单元格调整大小)?我假设此操作中根本没有涉及getTableCellRendererComponent,这完全是使用JLabel的paint方法和paint中重新定义的StretchIcon方法完成的。

我的理解是不正确的? 在方法中创建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;
    }
}

1 个答案:

答案 0 :(得分:4)

  

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

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

  

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

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

原因是,表格简单"油漆"结果本身,它没有"添加"以您习惯的方式使用组件。这通常被称为"千篇一律"或者"橡皮图章",因为该组件仅用作模板。

  

如何在需要时重新绘制已调整大小的图标(隐藏单元格然后再次显示,或单元格调整大小)?我假设此操作中根本没有涉及getTableCellRendererComponent,这完全是使用JLabel的paint方法和StretchIcon中重新定义的paint方法完成的。

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

该表将使用适当的TableCellRenderer

确定受影响的单元格并重新绘制它们

简而言之。不需要在JLabel内创建getTableCellRendererComponent的新实例。事实上,你根本不需要JLabel,因为DefaultTableCellRenderer来自JLabel,你应该只使用它。

我不知道StretchIcon是如何工作的,所以你可能别无选择,只能创建一个新实例,但如果可以,你可以考虑创建一个WeakHashMap键入{ {1}}值,它维护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; } cache ...

在阅读Concepts: Editors and Renderers

时可能值得