在单个单元格上应用TableCellRenderer

时间:2013-05-06 20:51:41

标签: java swing jtable tablecellrenderer

我试图能够在JTable中对单元格进行着色,但到目前为止,我只能在整个列上应用TableCellRenderer,这显然会出现故障。我有一个自定义JTable:

public class JColorTable extends JTable{
  (...)
  public void setCellColor(int col, int row, Color newColor) {
    getColumnModel().getColumn(col).setCellRenderer(new ColorField(col, row, newColor, background));
    repaint();
  }
}

ColorField看起来像这样:

class ColorField extends DefaultTableCellRenderer {

    (...))

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

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

        if (row == newRow && column == newCol) {
            l.setBackground(Color.red);
        } else {
            l.setBackground(defaultColor);
        }

        return l;
    }
}

当我在列中有单个单元格时,这就像魅力一样,但是当我尝试为该列中的另一个单元格着色时,前一个单元格被删除(由于ColorField中的条件不适用于前一列)。

有没有办法只将ColorField应用于单个单元格而不是整个列?如果是这样,怎么样?我害怕找不到合适的东西。

4 个答案:

答案 0 :(得分:3)

JTable有一个方法getCellRenderer()可以覆盖。当一个单元格需要渲染并在基于行和列返回一个单元格时调用它。

您的JTable需要记录每个单元格使用哪个渲染器(按行和列)。 2D数组可以使用它,或者Map,其中键是X,Y值。

添加一个方法来设置特定单元格上的渲染器(按行和列),然后就可以了。

class MyTable extends JTable {

    // all the other JTable stuff goes here too ...

    public TableCellRenderer getCellRenderer(int row, int column) {
        TableCellRenderer myRenderer = getCustomRenderer(row, column);
        if (myRenderer != null) {
            return myRenderer;
        }
        // else...
        return super.getCellRenderer(row, column);
    }

    private Map<Integer, Map<Integer, TableCellRenderer>> rendererMap = new ...;

    public void setCustomRenderer(int row, int column, TableCellRenderer renderer) {
        Map<Integer, TableCellRenderer> m1 = rendererMap.get(row);
        if (m1 == null) {
            m1 = new ...;
            rendererMap.put(row, m1);
        }
        m1.put(column, renderer);
    }

    public TableCellRenderer getCustomRenderer(int row, int column) {
        Map<Integer, TableCellRenderer> m1 = rendererMap.get(row);
        if (m1 == null) {
            return null;
        }
        return m1.get(column);
    }
}

getTableCellRenderer的默认版本使用在列上设置的渲染器(如果有),如果不是,则根据单元格内容的类使用渲染器。在许多情况下,默认单元格内容为Object。这取决于使用的TableModel

答案 1 :(得分:3)

就个人而言,我会避免任何要求您延长JTable的解决方案。主要原因是它使您的代码不那么容易,并且将渲染器与JTable的特定实现紧密耦合。它可能适合您的需求,但就个人而言,我总是试图看到更大的图景/潜力/重用。

请记住,单元格渲染器绑定到表格列。它并不意味着能够逐个单元地提供自定义渲染,本身。您可以做的是,根据渲染器中的一系列条件为每个单元格提供渲染逻辑。

我可能会将一些条件/格式引擎组合在一起,您可以使用它来传递单元格值和坐标,然后根据引擎特定实现的需要做出决策。

class ColorField extends DefaultTableCellRenderer {

    (...))

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

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

        // CellFormat is an object you create to hold the various aspects
        // of the cell format
        // You could also pass in the selected and focused flags if you
        // needed them...
        // getFormatEngine is a method you would write to provide
        // to gain access to the format engine
        CellFormat format = getFormatEngine().getFormatFor(value, row, column);
        setBackground(format.getBackground());
        setForeground(format.getForeground());
        setFont(format.getFont());
        // Any other properties you may wish to effect...

        return this;
    }
}

FormatEngine将成为决定如何最佳格式化给定单元格的基础。它应该能够提供“默认”格式

这意味着您可以为特定单元格类型设计“默认”渲染器,但能够根据您的需要提供自定义渲染,而无需多个if语句或扩展基础渲染

这也是条件格式引擎的基础,您可以针对给定值应用一系列条件,并根据结果返回适当的格式

答案 2 :(得分:0)

您需要列中每个单元格的一些颜色信息。此信息可以包含在值中:

class CellValue {
    Color getBackgroundColor() { ... }
    String getCellContent() { ... }
}

您的getTableCellRendererComponent()方法可能如下所示:

CellValue cellValue = (CellValue) value;
Color bgColor = cellValue.getBackgroundColor();
String text = cellValue.getCellContent();

JLabel l = (JLabel) super.getTableCellRendererComponent(table, text, isSelected, hasFocus, row, column);

l.setBackground(bgColor);

...

当然,您必须调整TableModel以存储CellValue实例。

答案 3 :(得分:0)

我认为实现这一目标的正确方法是通过ColorHighlighter。 这在the documentation中说。这是related issue in SO

注意:如果表允许排序,则必需来实现相应的ComponentAdapter及其dapter.convertRowIndexToModel