Sun Java Solaris Communities My SDN Account Join SDN
 
Swing Introduction

Swing

 

Bookshelf Index


Introduction | Download Chapter 18| Download Chapter 22
<< NEXT >>

Running the Code

Figure 18.2 shows StocksTable with custom rendering in action. Note the correct usage of color and icons, which considerably enhances the visualization of our data.

Improving visual communication Tables can be data intensive and consequently it can be very difficult for the viewer to quickly pick out the important information. The table in fig 18.1 highlighted this. In fig 18.2, we are improving the visual communication with the introduction of visual layers. The icons in the first column quickly tell the viewer whether a price is rising or falling. This is visually re-inforced with the red and green introduced on the change columns.

Red particularly is a very strong color. By introducing red and green only on the change columns and not across the entire row, we avoid the danger of the red becoming overpowering. If we had introduced red and green across the full width of the table, the colors may have become intrusive and impaired the visual communication.

18.4 Stocks Table: part III - Data Formatting

To further enhance the presentation of our stock data, in this section we wll take into account that actual stock prices (at least on NYSE and NASDAQ) are expressed in fractions of 32, not in decimals. Another issue that we will deal with is the volume of trade, which can reach hundreds of millions of dollars. Volume is not immediately legible without separating thousands and millions places with commas.


Click Figure 18.3 for full-scale image.
JTable with custom number formatting cell renderer to display fractions and comma-delimited numbers.

The Code: StocksTable.java

see \Chapter18\3


import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.io.*;
import java.text.*;

import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;
import javax.swing.table.*;

// Unchanged code from 
//section 18.3

class Fraction
{
  public int m_whole;
  public int m_nom;
  public int m_den;

  public Fraction(double value) {
    int sign = value <0 ? -1 : 1;
    value = Math.abs(value);
    m_whole = (int)value;
    m_den = 32;
    m_nom = (int)((value-m_whole)*m_den);
    while (m_nom!=0 && m_nom%2==0) {
      m_nom /= 2;
      m_den /= 2;
    }
    if (m_whole==0)
      m_nom *= sign;
    else
      m_whole *= sign;
  }

  public double doubleValue() {
    return (double)m_whole + 
             (double)m_nom/m_den;
  }

  public String toString() {
    if (m_nom==0)
      return ""+m_whole;
    else if (m_whole==0)
      return ""+m_nom+"/"+m_den;
    else
      return ""+m_whole+" 
               "+m_nom+"/"+m_den;
  }
}

class SmartLong
{
  protected static 
         NumberFormat FORMAT;

  static {
    FORMAT = 
     NumberFormat.getInstance();
    FORMAT.setGroupingUsed(true);
  }

  public long m_value;

  public SmartLong(long value) 
            { m_value = value; }

  public long longValue() 
            { return m_value; }

  public String toString() 
              { return FORMAT.format(
                          m_value); }
}

class ColorData
{
  public ColorData(Fraction data) {
    m_color = data.doubleValue() 
                 >= 0 ? GREEN : RED;
    m_data  = data;
  }

  // Unchanged code from section 18.3
}

class StockData
{
  public static ImageIcon ICON_UP = 
               new ImageIcon("ArrUp.gif");
  public static ImageIcon ICON_DOWN = 
             new ImageIcon("ArrDown.gif");
  public static ImageIcon ICON_BLANK = 
               new ImageIcon("blank.gif");

  public IconData  m_symbol;
  public String  m_name;
  public Fraction  m_last;
  public Fraction  m_open;
  public ColorData  m_change;
  public ColorData  m_changePr;
  public SmartLong  m_volume;

  public StockData(String symbol, 
                     String name, 
                      double last, 
   double open, double change, 
     double changePr, long volume) {
    m_symbol = 
       new IconData(getIcon(
                change), symbol);
    m_name = name;
    m_last = new Fraction(last);
    m_open = new Fraction(open);
    m_change = new ColorData(
            new Fraction(change));
    m_changePr = new ColorData(
            new Double(changePr));
    m_volume = new SmartLong(volume);
  }

  // Unchanged code from section 18.3
}

Understanding the Code

Class Fraction

This new data class encapsulates fractions with denominator 32 (or in a reduced form). Three instance variables represent the whole number, numerator, and denominator of the fraction. The only constructor takes a double parameter and carefully extracts these values, performing numerator and denominator reduction, if possible. Note that negative absolute values are taken into account.

Method doubleValue() performs the opposite task: it converts the fraction into a double value. Method toString() forms a String representation of the fraction.

Note that a zero whole number or a zero nominator are omitted to avoid unseemly output like "0 1/2" or "12 0/32".

Class SmartLong

This class encapsulates long values. The only constructor takes a long as parameter and stores it in the m_value instance variable. The real purpose of creating this class is the overridden toString() method, which inserts commas separating thousands, millions, etc. places. For this purpose we use the java.text.NumberFormat class. An instance of this class is created as a static variable, and formatting values using NumberFormat's format() method couldn't be easier.

Note: SmartLong cannot extend Long (although it would be natural), because java.lang.Long is a final class.

Note: We could use the different approach of just formatting the initial contents of our table's cells into text strings and perating on them without introducing new data classes. This approach, however, is not desirable from a design point of view, as it strips the data of its true nature: numbers.

Class ColorData

This class requires a new constructor to cooperate with the new Fraction data type. This third constructor takes a Fraction instance as parameter and uses its color attribute in the same way it did previously: green for positive values, and red for negative values.

Class StockData

This class uses new data types for its instance variables. The list of instance variables now looks like the following:

Field Type Data object Description
m_symbol IconData String Stock symbol (NYSE or NASDAQ)
m_name String N/A Company name
m_last Fraction N/A The price of the last trade
m_open Fraction N/A The price at the beginning of the trade day
m_change ColorData Fraction Absolute change in price
m_changePr ColorData Double Percent change in price
m_volume SmartLong N/A Day's volume of trade (in $) for this stock

The StockData constructor is modified accordingly. Meanwhile the parameters in the StockData constructor have not changed, so there is no need to make any changes to the data model class using StockData.

Running the Code

Figure 18.3 shows StocksTable in action with number formatting. Presented this way, our data looks much more familiar to most of those who follow the stock trade on a regular basis.

Talking the Users language In this example, we have changed the rendering of the stock prices into fractions rather than decimals. This is a good example of providing better visual communication by speaking the same language as the viewers. In the North American stock markets, prices are quoted in fractional amounts of dollars rather than dollars and cents. Switching to this type of display helps the application to communicate more quickly and more influentially to the viewer, improving usability.

Page 1 2 3 4 5 6 7 8 9 10 11

<< NEXT >>
Download Chapter 18| Download Chapter 22]