classpath-patches
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[cp-patches] FYI: JTable fixes


From: Roman Kennke
Subject: [cp-patches] FYI: JTable fixes
Date: Wed, 18 May 2005 16:10:17 +0200
User-agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.2.1) Gecko/20021204

Hi,

I added several default cell renderers to JTable, that enable cell values of the following types to be rendered specially:

Boolean (CheckBox)
Double (right-aligned and converted with NumberFormat)
Float (right-aligned and converted with NumberFormat)
Number (right-aligned)
Icon (as Icon)
Date (converted using DateFormat)

all other objects are rendered per default as String as returned by toString()

I also have changed the algorithm in distributeSpill() which was trying to do the algorithm described in Suns API documentation, but failed to do. The result was mostly crappy, possibly due to rounding errors or due to misunderstanding of the algo.

I implemented a rather naive approach of distributing the DELTA, which is to evenly distribute it. This does not respect the min/pref/max sizes of the column, so it is still not 100% perfect, but at least it looks very much more like it should.

2005-05-18  Roman Kennke  <address@hidden>

       * javax/swing/JTable.java:
(BooleanCellRenderer): Added default renderer for Boolean cell values.
       (DateCellRenderer): Added default renderer for Date cell values.
       (DoubleCellRenderer): Added default renderer for Double cell values.
       (FloatCellRenderer): Added default renderer for Float cell values.
       (NumberCellRenderer): Added default renderer for Number cell values.
       (IconCellRenderer): Added default renderer for Icon cell values.
       (createDefaultRenderers): Include new default renderers.
       (distributeSpill): Fix algorithm to do a nice layout, if still not
       beeing 100% perfect.
       (doLayout): Correctly calculate the spill variable.

/Roman

Index: javax/swing/JTable.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/JTable.java,v
retrieving revision 1.25
diff -u -r1.25 JTable.java
--- javax/swing/JTable.java     26 Jan 2005 20:57:45 -0000      1.25
+++ javax/swing/JTable.java     18 May 2005 14:01:23 -0000
@@ -43,6 +43,9 @@
 import java.awt.Dimension;
 import java.awt.Point;
 import java.awt.Rectangle;
+import java.text.DateFormat;
+import java.text.NumberFormat;
+import java.util.Date;
 import java.util.Hashtable;
 import java.util.Vector;
 
@@ -71,6 +74,212 @@
   implements TableModelListener, Scrollable, TableColumnModelListener,
              ListSelectionListener, CellEditorListener, Accessible
 {
+
+  /**
+   * A cell renderer for boolean values.
+   */
+  private class BooleanCellRenderer
+    extends DefaultTableCellRenderer
+  {
+
+    /**
+     * The CheckBox that is used for rendering.
+     */
+    private JCheckBox checkBox = new JCheckBox();
+
+    /**
+     * Returns the component that is used for rendering the value.
+     *
+     * @param table the JTable
+     * @param value the value of the object
+     * @param isSelected is the cell selected?
+     * @param hasFocus has the cell the focus?
+     * @param row the row to render
+     * @param column the cell to render
+     * 
+     * @return this component (the default table cell renderer)
+     */
+    public Component getTableCellRendererComponent(JTable table, Object value,
+                                                   boolean isSelected,
+                                                   boolean hasFocus, int row,
+                                                   int column)
+    {
+      Boolean boolValue = (Boolean) value;
+      checkBox.setSelected(boolValue.booleanValue());
+      return checkBox;
+    }
+  }
+
+  /**
+   * A cell renderer for Date values.
+   */
+  private class DateCellRenderer
+    extends DefaultTableCellRenderer
+  {
+    /**
+     * Returns the component that is used for rendering the value.
+     *
+     * @param table the JTable
+     * @param value the value of the object
+     * @param isSelected is the cell selected?
+     * @param hasFocus has the cell the focus?
+     * @param row the row to render
+     * @param column the cell to render
+     * 
+     * @return this component (the default table cell renderer)
+     */
+    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)
+        {
+          Date dateValue = (Date) value;
+          DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT);
+          setText(df.format(dateValue));
+        }
+      return this;
+    }
+  }
+
+  /**
+   * A cell renderer for Double values.
+   */
+  private class DoubleCellRenderer
+    extends DefaultTableCellRenderer
+  {
+    /**
+     * Creates a new instance of NumberCellRenderer.
+     */
+    public DoubleCellRenderer()
+    {
+      setHorizontalAlignment(JLabel.RIGHT);
+    }
+
+    /**
+     * Returns the component that is used for rendering the value.
+     *
+     * @param table the JTable
+     * @param value the value of the object
+     * @param isSelected is the cell selected?
+     * @param hasFocus has the cell the focus?
+     * @param row the row to render
+     * @param column the cell to render
+     * 
+     * @return this component (the default table cell renderer)
+     */
+    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 Double)
+        {
+          Double doubleValue = (Double) value;
+          NumberFormat nf = NumberFormat.getInstance();
+          setText(nf.format(doubleValue.doubleValue()));
+        }
+      return this;
+    }
+  }
+
+  /**
+   * A cell renderer for Float values.
+   */
+  private class FloatCellRenderer
+    extends DefaultTableCellRenderer
+  {
+    /**
+     * Creates a new instance of NumberCellRenderer.
+     */
+    public FloatCellRenderer()
+    {
+      setHorizontalAlignment(JLabel.RIGHT);
+    }
+
+    /**
+     * Returns the component that is used for rendering the value.
+     *
+     * @param table the JTable
+     * @param value the value of the object
+     * @param isSelected is the cell selected?
+     * @param hasFocus has the cell the focus?
+     * @param row the row to render
+     * @param column the cell to render
+     * 
+     * @return this component (the default table cell renderer)
+     */
+    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 Float)
+        {
+          Float floatValue = (Float) value;
+          NumberFormat nf = NumberFormat.getInstance();
+          setText(nf.format(floatValue.floatValue()));
+        }
+      return this;
+    }
+  }
+
+  /**
+   * A cell renderer for Number values.
+   */
+  private class NumberCellRenderer
+    extends DefaultTableCellRenderer
+  {
+    /**
+     * Creates a new instance of NumberCellRenderer.
+     */
+    public NumberCellRenderer()
+    {
+      setHorizontalAlignment(JLabel.RIGHT);
+    }
+  }
+
+  /**
+   * A cell renderer for Icon values.
+   */
+  private class IconCellRenderer
+    extends DefaultTableCellRenderer
+  {
+    /**
+     * Returns the component that is used for rendering the value.
+     *
+     * @param table the JTable
+     * @param value the value of the object
+     * @param isSelected is the cell selected?
+     * @param hasFocus has the cell the focus?
+     * @param row the row to render
+     * @param column the cell to render
+     * 
+     * @return this component (the default table cell renderer)
+     */
+    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 Icon)
+        {
+          Icon iconValue = (Icon) value;
+          setIcon(iconValue);
+        }
+      return this;
+    }
+  }
+
   private static final long serialVersionUID = 3876025080382781659L;
 
 
@@ -476,7 +685,12 @@
 
   protected void createDefaultRenderers()
   {
-    //FIXME: Create the renderer object.
+    setDefaultRenderer(Boolean.class, new BooleanCellRenderer());
+    setDefaultRenderer(Number.class, new NumberCellRenderer());
+    setDefaultRenderer(Double.class, new DoubleCellRenderer());
+    setDefaultRenderer(Double.class, new FloatCellRenderer());
+    setDefaultRenderer(Date.class, new DateCellRenderer());
+    setDefaultRenderer(Icon.class, new IconCellRenderer());
   }
   
   /**
@@ -1580,44 +1794,22 @@
 
 
   /**
-   * Sun javadocs describe an unusual implementation of
-   * <code>doLayout</code> which involves some private interfaces. We try
-   * to implement the same algorithm as is documented, but using the
-   * columnModel directly. We still use a private helper method, but it has
-   * a simpler signature.
+   * This distributes the superfluous width in a table evenly on its columns.
+   *
+   * The implementation used here is different to that one described in
+   * the JavaDocs. It is much simpler, and seems to work very well.
+   *
+   * TODO: correctly implement the algorithm described in the JavaDoc
    */
-
   private void distributeSpill(TableColumn[] cols, int spill)
   {
-    int MIN = 0;
-    int MAX = 0;
-    int PREF = 0;
-
-    int[] min = new int[cols.length];
-    int[] max = new int[cols.length];
-    int[] pref = new int[cols.length];
-
-    for (int i = 0; i < cols.length; ++i)
+    int average = spill / cols.length;
+    for (int i = 0; i < cols.length; i++)
       {
-        pref[i] = cols[i].getPreferredWidth();
-        min[i] = cols[i].getMinWidth();
-        max[i] = cols[i].getMaxWidth();
-        PREF += pref[i];
-        MIN += min[i];
-        MAX += max[i];
+        cols[i].setWidth(cols[i].getWidth() + average);
       }
-
-    for (int i = 0; i < cols.length; ++i)
-      {
-        int adj = 0;
-        if (spill > 0)          
-          adj = (spill * (pref[i] - min[i])) / (PREF - MIN);
-        else
-          adj = (spill * (max[i] - pref[i])) / (MAX - PREF);
-        cols[i].setWidth(pref[i] + adj);        
-      }    
   }
-  
+
   public void doLayout()
   {
     TableColumn resizingColumn = null;
@@ -1643,7 +1835,7 @@
           rCol = i;
       }
 
-    int spill = prefSum - getWidth();
+    int spill = getWidth() - prefSum;
 
     if (resizingColumn != null)
       {

reply via email to

[Prev in Thread] Current Thread [Next in Thread]