Search code examples
javaswingjtabletablecellrenderer

Custom table cell renderer having no effect


I tried to implement the example for a custom TableCellRenderer from here (I tried other examples, too). Whatever I did, my custom TableCellRenderer had absolutely no effect, so I think I'm doing something wrong on a different level. Could anyone please explain to me what exactly I'm doing wrong? Here's my code:

import java.text.DecimalFormat;
import java.util.Random;

import javax.swing.Icon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingConstants;
import javax.swing.border.EmptyBorder;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;

public class Test {
  public static void main(String[] args) {
    // Show GUI
    java.awt.EventQueue.invokeLater(new Runnable() {
      @Override
      public void run() {
        GUI gui = new GUI();

        int numRows = 5;
        int numCols = 5;

        DefaultTableModel tableModel = new DefaultTableModel(0,
          numCols);

        // Add rows
        for (int i = 0; i < numRows; i++) {
          Float[] row = new Float[numCols];

          // Build columns
          for (int j = 0; j < numCols; j++) {
            Random random = new Random();
            row[j] = random.nextFloat();
          }
          tableModel.addRow(row);
        }

        JTable table = new JTable(tableModel);
        table.setDefaultRenderer(Float.class, new DecRenderer(
          new DecimalFormat("##")));

        JScrollPane scrollPane = new JScrollPane(table);
        gui.getContentPane()
          .add(scrollPane, BorderLayout.CENTER);

      }
    });
  }
}

class GUI extends JFrame {
  private static final long serialVersionUID = 1L;

  public GUI() {
    setTitle("GUI");
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setBounds(100, 100, 350, 400);
    setLocationRelativeTo(null);
    setVisible(true);

    JPanel contentPane = new JPanel();
    contentPane.setBorder(new EmptyBorder(10, 10, 10, 10));
    contentPane.setLayout(new BorderLayout(0, 0));

    setContentPane(contentPane);
  }
}

// Source: https://stackoverflow.com/questions/2833482/
// how-to-represent-double-values-as-circles-in-a-2d-matrix-in-java/
// 2834484#2834484
@SuppressWarnings("serial")
class DecRenderer extends DefaultTableCellRenderer implements
  Icon {

  private static final int SIZE = 32;
  private static final int HALF = SIZE / 2;
  DecimalFormat            df;

  public DecRenderer(DecimalFormat df) {
    this.df = df;
    this.setIcon(this);
    this.setHorizontalAlignment(SwingConstants.RIGHT);
    this.setBackground(Color.lightGray);
  }

  @Override
  protected void setValue(Object value) {
    setText((value == null) ? "" : df.format(value));
  }

  @Override
  public void paintIcon(Component c, Graphics g, int x, int y) {
    Graphics2D g2d = (Graphics2D) g;
    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
      RenderingHints.VALUE_ANTIALIAS_ON);
    g2d.setColor(Color.blue);
    double v = Double.valueOf(this.getText());
    int d = (int) (v * SIZE);
    int r = d / 2;
    g2d.fillOval(x + HALF - r, y + HALF - r, d, d);
  }

  @Override
  public int getIconWidth() {
    return SIZE;
  }

  @Override
  public int getIconHeight() {
    return SIZE;
  }
}

Solution

  • That happens because DefaultTableModel in getColumnClass returns Object.class for all your columns(in your case).

    Quick fix is change model like next:

     DefaultTableModel tableModel = new DefaultTableModel(0,numCols) {
            @Override
            public Class<?> getColumnClass(int columnIndex) {
                return Float.class;
            }
        };