1

I need to render a java.util.Date in a JTable. I've implemented a custom renderer that extends DefaultTableCellRenderer (code appears below). I've set it as the renderer for the column, but the method getTableCellRendererComponent() never gets called.

This is a pretty common problem, but none of the solutions I've seen work.

public class DateCellRenderer extends DefaultTableCellRenderer {

    String sdfStr = "yyyy-MM-dd HH:mm:ss.SSS";
    SimpleDateFormat sdf = new SimpleDateFormat(sdfStr);

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


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

        if (value instanceof Date) {

            this.setText(sdf.format((Date) value));
        }
        else
            logger.info("class: " + value.getClass().getCanonicalName());

        return this;
    }
}

I've installed the custom renderer (and verified that it has been installed) like this:

DateCellRenderer dcr = new DateCellRenderer();
table.getColumnModel().getColumn(2).setCellRenderer(dcr);

I've also tried

table.setDefaultRenderer( java.util.Date.class, dcr );

Any idea why the renderer gets installed, but never called?

Abra
  • 19,142
  • 7
  • 29
  • 41
Dean Schulze
  • 9,633
  • 24
  • 100
  • 165
  • 1
    I never encountered such behavior. Could you post an [SSCCE](http://sscce.org/) illustrating this ? And how did you determine that the method is never called ? In [this answer](http://stackoverflow.com/questions/8776754/selecting-password-row-and-pasting-in-notepad-reveals-the-password/8776974#8776974) I used the `setDefaultRenderer` without any problem – Robin Mar 23 '12 at 07:55

5 Answers5

3

I wrote the following code with your renderer and found no problem. I hope this helps.

import java.awt.BorderLayout;
import java.awt.Component;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Vector;

import javax.swing.JFrame;
import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;

public class DateCellRenderer extends DefaultTableCellRenderer {
    private static final long serialVersionUID = 4685939347849124147L;

    String sdfStr = "yyyy-MM-dd HH:mm:ss.SSS";
    SimpleDateFormat sdf = new SimpleDateFormat(sdfStr);

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

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

        if (value instanceof Date) {
            this.setText(sdf.format((Date) value));
        } else {
            System.out.println("class: " + value.getClass().getCanonicalName());
        }

        return this;
    }

    public static void main(String[] args) {
        // Create new Frame
        JFrame frame = new JFrame("Debug Frame");
        frame.setSize(200, 200);
        frame.setLayout(new BorderLayout());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);


        DefaultTableModel data = new DefaultTableModel();
        // add one colunb to the data model
        data.addColumn("Testing");
        Vector<Date> dates = new Vector<Date>();
        dates.add(new Date(Calendar.getInstance().getTimeInMillis()));


        data.addRow(dates);
        data.addRow(dates);
        data.addRow(dates);

        JTable table = new JTable(data);
        DateCellRenderer dcr = new DateCellRenderer();
        table.getColumnModel().getColumn(0).setCellRenderer(dcr);

        frame.add(table, BorderLayout.CENTER);
        frame.setVisible(true);
    }
}
Reg
  • 10,717
  • 6
  • 37
  • 54
  • 1
    It's interesting that it works in isolation. That leads me to believe that something else is interfering with invoking the new renderer. – Dean Schulze Mar 23 '12 at 13:14
0

I encountered the same problem. And I fixed it using this documention:

static class DateRenderer extends DefaultTableCellRenderer {
    DateFormat formatter;
    public DateRenderer() { super(); }

    public void setValue(Object value) {
        if (formatter==null) {
            formatter = DateFormat.getDateInstance();
        }
        setText((value == null) ? "" : formatter.format(value));
    }
}
matcauthon
  • 2,261
  • 1
  • 24
  • 41
0

I had the same problem, and the problem was simply that I had copy / pasted the method signature from a web page. I encountered that issue when beginning to code, and usually don't do it anymore, but I did this time without thinking. I thought I'd mention it here since I came here in my search looking for why it may have been happening to me.

kjp
  • 51
  • 4
-1

I am able to work around this by modifying the getValueAt() method in my TableModel to return a properly formatted date String. This isn't what a TableModel is for and I still need to understand why the installed custom rendere isn't working.

Dean Schulze
  • 9,633
  • 24
  • 100
  • 165
  • -1 for doing something you know is the wrong thingy to do ;-) – kleopatra Mar 23 '12 at 08:56
  • Since the renderer won't work I have to work around it some how. And getting my project delivered on time is the RIGHT thing to do. – Dean Schulze Mar 23 '12 at 13:12
  • mileage may vary, but delivering on time if rather worthless if it's faulty - that's always a time bomb which will explode sooner or later ;-) – kleopatra Mar 23 '12 at 13:18
  • kleopatra, I've already run into the time bomb - setting a cell renderer doesn't call that renderer. It works on the SSCCE above, but not in a real Swing app. – Dean Schulze Mar 23 '12 at 19:24
  • it works in every real-world Swing app except yours :-) Check: a) when setting a per-column renderer: make sure the columns are not re-created after, f.i. by setting a new model or the model firing a structureChanged b) when setting per-classs, make sure the model returns Date for the column – kleopatra Mar 24 '12 at 10:19
  • Are you sure that tableModel.fireTableStructureChanged() resets the renderers? The JavaDocs don't mention it. I do fire structureChanged and then install the new renderer, but it has no effect. My table model changes internally after each query requiring the structureChanged event. – Dean Schulze Mar 29 '12 at 17:56
  • by default the columns are recreated on structureChanged - so all state of the old columnss is lost, trivially :-) – kleopatra Mar 30 '12 at 09:36
  • That's what you said above. I'm asking where that is documented. I re-assign a new default renderer after firing structureChanged but the new renderer doesn't get invoked. I may be running into other undocumented behavior and finding the documentation for what you are talking about may help. – Dean Schulze Mar 30 '12 at 13:30
-1
  1. super.getTableCellRendererComponent returns a Component, but you're not using it and not returning it.
  2. Set your Rendenrer with setDefaultRenderer() also for String class (and maybe for Object class too)
  3. Instead of setting your Renderer on particulat column set it for the entire Table and check in your Renderer code the column number and render your stuff there. That should work (or google for it :-)
lzdt
  • 489
  • 1
  • 6
  • 17
  • @kleopatra damn, but at least someone found it. But still 2 questions: why is using Component returned from super call is wrong and why is using Renderer on entire table and checking column number to apply rendering effect on that particular column is wrong? – lzdt Mar 23 '12 at 19:06