Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / First Aid / June 2005

Tip: Looking for answers? Try searching our database.

formatting floats in a table

Thread view: 
farseer - 27 Jun 2005 07:42 GMT
Hi,
i have a table whose columns can contain either Strings, Integers, or
Floats.  I also allow sorting by clicking on the header of a column.

my question is, i need to display only two decimal places for columns
that display floats.  How can i do this and still maintain accurate
sorting for those columns?  Currently, it seems most of the formating
functions return Strings, and that may cause the sorting to be
incorrect for columns that are suppose to display numbers.

Also i am trying to do this generically using a custom
TableCellRenderer class i have written.  This renderer has a member
variable called "formatString". Basically, when the JTable is
initalized, i read some config info, one of which tells me what columns
need formatting and how they should be formatted.  I then instantiate
the TableCellRenderer class, assign the formatString (if required),
then call TableColumn.setCellRenderer.
Now i just need to know how i can apply that formatString to the Value
and still maintain the underlying class type of Value so that i can be
properly sorted....
Roland - 27 Jun 2005 13:23 GMT
> Hi,
> i have a table whose columns can contain either Strings, Integers, or
[quoted text clipped - 16 lines]
> and still maintain the underlying class type of Value so that i can be
> properly sorted....

It's not clear to me how you do the sorting. I'm assuming that you are
using your own TableModel that takes care of this. Then, make sure that
your TableModel (if you have one) returns the correct Class for each
column in the getColumnClass method (i.e. Float.class for the Float
columns). If this is the case then you can set the default renderer of
your table for Float.class to be your TableCellRenderer:
   YourTableModel yourTableModel = ...
   YourCellRenderer yourCellRenderer = ...
   JTable yourTable = new JTable(yourTableModel);
   yourTable.setDefaultRenderer(Float.class, yourCellRenderer);

Otherwise (or alternatively) you can specify a TableCellRenderer for
each column separately:
   yourTable.getColumnModel()
            .getColumn(1).setCellRenderer(yourCellRenderer);

Your TableCellRenderer could use a DecimalFormat instance, so it can
format Float values to two decimal places. The code below shows a
complete example:

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

public class TableExample {

   public static void main(String[] args) {

      Object[][] rowData = {
            {new Float(0.0),new Float(0.1),new Integer( 2),"[0,3]"},
            {new Float(1.0),new Float(1.1),new Integer(12),"[1,3]"},
            {new Float(2.0),new Float(2.1),new Integer(22),"[2,3]"}};
      Object[] colNames = { "A", "B", "C", "D" };

      YourTableModel yourTableModel =
                        new YourTableModel(rowData, colNames);
      JTable yourTable = new JTable(yourTableModel);
      yourTable.setDefaultRenderer(Float.class,
                                   new YourCellRenderer("0.0"));
      yourTable.getColumnModel().getColumn(1).setCellRenderer(
            new YourCellRenderer("0.00"));

      JFrame app = new JFrame();
      app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      app.getContentPane().setLayout(new BorderLayout());
      app.getContentPane().add(new JScrollPane(yourTable),
                              BorderLayout.CENTER);
      app.setSize(400, 300);
      app.setLocationRelativeTo(null);
      app.setVisible(true);
   }
}

class YourCellRenderer extends DefaultTableCellRenderer {
   private final NumberFormat formatter;

   public YourCellRenderer() {
      this.formatter = NumberFormat.getNumberInstance();
      setHorizontalAlignment(JLabel.RIGHT);
   }

   public YourCellRenderer(String format) {
      if (format == null) {
         throw new IllegalArgumentException("format cannot be null");
      }
      this.formatter = new DecimalFormat(format);
      setHorizontalAlignment(JLabel.RIGHT);
   }

   protected void setValue(Object value) {
      if (value instanceof Number) {
         value = formatter.format(value);
      }
      super.setValue(value);
   }
}

class YourTableModel extends DefaultTableModel {
   public YourTableModel(Object[][] data, Object[] columnNames) {
      super(data, columnNames);
   }

   public Class getColumnClass(int columnIndex) {
      switch (columnIndex) {
      case 0:
         return Float.class;
      case 1:
         return Float.class;
      case 2:
         return Integer.class;
      case 3:
         return String.class;
      default:
         return Object.class;
      }
   }
}

Signature

Regards,

Roland de Ruiter
` ___      ___
`/__/ w_/ /__/
/  \ /_/ /  \

Thomas G. Marshall - 27 Jun 2005 14:59 GMT
Roland coughed up:

...[rip]...

> Your TableCellRenderer could use a DecimalFormat instance, so it can
> format Float values to two decimal places. The code below shows a
> complete example:

This raises to me an important point, to the side of this discussion, and
it's one that is often overlooked.

When creating applications that might be run /anywhere/ in any country,
which is pretty much the norm since the internet, I use NumberFormat and
it's descendents religiously.

In fact, in general, it's a /very/ good idea IMO to just start using
NumberFormat.{parse,format})() wherever possible.

You will:

1. No doubt eventually someday have a user enter in

       1.000,00

in the UK.

2. It is often glitzy to have precise control over the displaying of numbers
with separators (comma, period, whatever).  Furthermore there are some
locales which like these things separated by 4 digits, and then change the
rules for larger numbers.  This is all built in to java automatically.

3. The issue with tables when using formatting is that you need to be
careful to supply the correct sorting mechanism, so that 1,000, for example,
does not become lexically sorted.  This is always the case anyway, you must
sort by the numerical value, but this isn't always adhered to and I've seen
code place 10 before 2 when sorting on a numerical column.

...[rip]...

Signature

Doesn't /anyone/ know where I can find a credit card company that
emails me the minute something is charged to my account?

farseer - 27 Jun 2005 21:53 GMT
Thank you for the responses.

1.  I would prefer setting a renderer for each column, rather than
assigning renderer for datatypes of that table.  This is simply because
of the way i am implementing this.  I have an interface named IBehavior
that declares one method, "doBehavior()".  My TableCellRender contains
a list of Behaviors.  Behaviors are rendering specific actions that
should occur for a given column/cell (i.e. change
foreground/background/border colors depending on the value being
shown).  This way i can add multiple behaviors that should be executed
for a given column/cell and simply iterate thru the Behavior list for
that column and call doBheavior.   I think i can implment my Formatter
as simply another IBehavior

2.  I think you may have answered my question.  Currently, i do use a
custom TableModel, and it does indeed override getColumnClass to return
value.getClass.  This is how i have gotten sorting to work correctly
(before it sorting was incorrect because everything was being treated
as String).
The following snippet of your code i think answers my question:

   protected void setValue(Object value) {
      if (value instanceof Number) {
         value = formatter.format(value);
      }
      super.setValue(value);
   }

Above, formatter.format(value) will return a String.  What you are
saying is that this does not matter for sorting, since my sorting is
being driven off the TableModel and there my getColumnClass method will
return the correct Class Type.  Basically, the code above is strictly
for display purposes...and should not affect my sorting, is that
correct?


Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.