Dynamic Date Formatting

|

I’ve noticed a neat feature in Path Finder where it changes the date format used to display time stamps in the main table based on the width of the column. In rvSnoop I was allowing the user to set a preferred format as a configuration option, but this seems much better.

It turns out that this is pretty easy to achieve in Java, just use the following class:

private static class DateCellRenderer extends DefaultTableCellRenderer {
    // Or load these from a user preference...
    private static final DateFormat[] FORMATS = {
        new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"),
        new SimpleDateFormat("yy-MM-dd HH:mm:ss.SSS"),
        new SimpleDateFormat("MM/dd HH:mm:ss.SSS"),
        new SimpleDateFormat("HH:mm:ss.SSS"),
        new SimpleDateFormat("HH:mm:ss.SS"),
        new SimpleDateFormat("HH:mm:ss.S"),
        new SimpleDateFormat("HH:mm:ss"),
        new SimpleDateFormat("HH:mm") };
    private int currentWidth;
    private Font currentFont;
    private DateFormat currentFormat;
    public Component getTableCellRendererComponent(JTable table, Object value,
            boolean isSelected, boolean hasFocus, int row, int col) {
        final DateFormat format = getFormat(table.getColumnModel().getColumn(col).getWidth(), table);
        final String displayed = value != null ? format.format((Date) value) : "";
        return super.getTableCellRendererComponent(table, displayed, isSelected, hasFocus, row, col);
    }
    private DateFormat getFormat(int width, JTable table) {
        final Font font = table.getFont();
        if (currentWidth != width) currentFormat = null;
        if (currentFont == null || !currentFont.equals(font)) currentFormat = null;
        if (currentFormat == null) {
            currentWidth = width;
            currentFont = font;
            final Date date = new Date();
            final FontMetrics metrics = table.getFontMetrics(font);
            for (int i = 0, imax = FORMATS.length; i < imax; ++i) {
                final int dateWidth = metrics.stringWidth(FORMATS[i].format(date));
                if (dateWidth < width) {
                    currentFormat = FORMATS[i];
                    break;
                }
            }
            if (currentFormat == null) {
                currentFormat = FORMATS[FORMATS.length - 1];
            }
        }
        return currentFormat;
    }
}
public class DateCellRenderer extends DefaultTableCellRenderer {

  private static final DateFormat[] FORMATS = {
    new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"),
    new SimpleDateFormat("HH:mm:ss.SSS"),
    new SimpleDateFormat("HH:mm:ss")};
  private int currentWidth;
  private Font currentFont;
  private DateFormat currentFormat;

  public Component getTableCellRendererComponent(
      JTable table, Object value, boolean isSelected,
      boolean hasFocus, int row, int col) {
    int w = table.getColumnModel().getColumn(col).getWidth();
    DateFormat format = getFormat(w, table);
    String s = value != null ? format.format((Date) value) : "";
    return super.getTableCellRendererComponent(
        table, s, isSelected, hasFocus, row, col);
  }

  private DateFormat getFormat(int width, JTable table) {
    Font font = table.getFont();
    if (currentWidth != width) currentFormat = null;
    if (currentFont != font) currentFormat = null;
    if (currentFormat == null) {
      currentWidth = width;
      currentFont = font;
      Date date = new Date();
      FontMetrics metrics = table.getFontMetrics(font);
      for (int i = 0, imax = FORMATS.length; i < imax; ++i) {
        DateFormat format = FORMATS[i];
        String dateString = format.format(date);
        int dateWidth = metrics.stringWidth(dateString);
        if (dateWidth < width) {
          currentFormat = format;
          break;
        }
      }
      if (currentFormat == null) {
        currentFormat = FORMATS[FORMATS.length - 1];
      }
    }
    return currentFormat;
  }
}

You will need to register it with your JTable like so myTable.getColumnModel().getColumn(0).setCellRenderer(myRenderer); and away you go. You can have more or less format options by altering the static array in the class.

About this Entry

This page contains a single entry by Ian Phillips published on April 17, 2006 5:12 PM.

rvSnoop was the previous entry in this blog.

Play Pumps is the next entry in this blog.

Find recent content on the main index or look in the archives to find all content.

Pages

Powered by Movable Type 4.1