Render table cells

Renderers customize how data is presented. For example, one may customize the rendering of table cells, table column headers, or tree nodes.

To render table cells as desired, first ensure that the table model implements getColumnClass. This will ensure Swing selects the most appropriate default renderer for each column.

If the default renderer is inadequate, then an implementation of TableCellRenderer (which has only one method - getTableCellRendererComponent) must be defined, in one of two ways:

It's important to note that getTableCellRendererComponent: To use your custom renderer in a table, pass it to TableColumn.setCellRenderer():
myTable.getColumnModel().getColumn(idx).setCellRenderer(new MyRenderer());
Example 1

The default action of setValue is to place the result of toString into a cell. This value may not be appropriate.

Here, Stock.toString would place unwanted data in the cell. The setValue method is overridden to customize both the text placed in a cell, and its associated tooltip:

package hirondelle.stocks.table;

import javax.swing.table.*;
import hirondelle.stocks.quotes.Stock;
import hirondelle.stocks.util.Util;

/**
* Display a {@link Stock} in a table cell by placing the
* full name in the cell, and by providing its Yahoo ticker 
* (including suffix for the {@link hirondelle.stocks.quotes.Exchange}) as tooltip.
*/
final class RenderStockName extends DefaultTableCellRenderer {
  
  @Override public void setValue(Object aValue) {
    Object result = aValue;
    if ((aValue != null) && (aValue instanceof Stock)) {
      Stock stock = (Stock) aValue;
      result = stock.getName();
      setTooltip(stock);
    } 
    super.setValue(result);
  }

  private void setTooltip(Stock aStock) {
    StringBuilder tooltip = new StringBuilder("Yahoo Ticker: ");
    tooltip.append(aStock.getTicker());
    String suffix = aStock.getExchange().getTickerSuffix();
    if (Util.textHasContent(suffix)) {
      tooltip.append(".");
      tooltip.append(suffix);
    }
    setToolTipText(tooltip.toString());
  }   
} 

Example 2

Use the current locale to render a Number as a currency:

package hirondelle.stocks.table;

import javax.swing.table.*;
import javax.swing.*;
import java.text.NumberFormat;

/**
* Display a <tt>Number</tt> in a table cell in the format defined by  
* {@link NumberFormat#getCurrencyInstance()}, and aligned to the right.
*/
final class RenderPrice extends DefaultTableCellRenderer {
  
  RenderPrice() { 
    setHorizontalAlignment(SwingConstants.RIGHT);  
  }
  
  @Override public void setValue(Object aValue) {
    Object result = aValue;
    if ((aValue != null) && (aValue instanceof Number)) {
      Number numberValue = (Number)aValue;
      NumberFormat formatter = NumberFormat.getCurrencyInstance();
      result = formatter.format(numberValue.doubleValue());
    } 
    super.setValue(result);
  }   
} 

Example 3

Render as red or green, according to the sign of a Number. The implementation overrides getTableCellRendererComponent instead of setValue, and returns a this reference.

package hirondelle.stocks.table;

import javax.swing.table.*;
import javax.swing.*;
import java.awt.*;

/**
* Display a <tt>Number</tt> in a table cell as either red (for negative values)
* or green (for non-negative values), and aligned on the right.
*
* <P>Note that this class will work with any <tt>Number</tt> -  
* <tt>Double</tt>, <tt>BigDecimal</tt>, etc.
*/
final class RenderRedGreen extends DefaultTableCellRenderer {
  
  RenderRedGreen () {
    setHorizontalAlignment(SwingConstants.RIGHT);   
  }
  
  @Override public Component getTableCellRendererComponent(
    JTable aTable, Object aNumberValue, boolean aIsSelected, 
    boolean aHasFocus, int aRow, int aColumn
  ) {  
    /* 
    * Implementation Note :
    * It is important that no 'new' objects be present in this 
    * implementation (excluding exceptions):
    * if the table is large, then a large number of objects would be 
    * created during rendering.
    */
    if (aNumberValue == null) return this;
    Component renderer = super.getTableCellRendererComponent(
      aTable, aNumberValue, aIsSelected, aHasFocus, aRow, aColumn
    );
    Number value = (Number)aNumberValue;
    if (value.doubleValue() < 0) {
      renderer.setForeground(Color.red);
    }
    else {
      renderer.setForeground(fDarkGreen);
    }
    return this;
  }
  
  // PRIVATE 
  
  //the default green is too bright and illegible
  private Color fDarkGreen = Color.green.darker();
} 

Here's an illustration of all three example renderers:

Illustration of above renderers

See Also :
Sort table rows