Easy to Learn Java: Programming Articles, Examples and Tips

Start with Java in a few days with Java Lessons or Lectures

Home

Code Examples

Java Tools

More Java Tools!

Java Forum

All Java Tips

Books

Submit News
Search the site here...
Search...
 

Swing Chapter 18. (Advanced topics) Tables. Easy for reading, Click here!

Custom Search
Swing Chapter 18. (Advanced topics) Tables. Easy for reading, Click here!

[ Return to Swing (Book) ]

Page: 5/9 



Previous Page Previous Page (4/9) - Next Page (6/9) Next Page
Subpages: 1. JTable  
2.
Stocks Table: part I - Basic JTable example 
3.
Stocks Table: part II - Custom renderers 
4. Stocks Table: part III - Data formatting 
5. Stocks Table: part IV - Sorting columns 
6.
Stocks Table: part V - JDBC
7.
Stocks Table: part VI - Column addition and removal
8.
Expense report application
9.
JavaBeans property editor

18.5  Stocks Table: part IV - sorting columns

Note: This and the following StocksTable examples require Java 2 as they make use of the new java.util.Collections functionality.

In this section we add the ability to sort any column in ascending or descending order. The most suitable graphical element for selection of sort order are the column headers. We adopt the following model for our sorting functionality:

1.       A single click on the header of a certain column causes the table to re-sort based on this column.

2.       A repeated click on the same column changes the sort direction from ascending to descending and vice versa.

3.       The header of the column which provides the current sorting should be marked.

To do this we add a mouse listener to the table header to capture mouse clicks and trigger a table sort. Fortunately sorting can be accomplished fairly easily using the new Collections functionality in Java 2.

Note: Class java.util.Collections contains a set of static methods used to manipulate Java collections, including java.util.Vector which is used in this example.

We use the java.util.Collections.sort(List lst, Comparator c) method to sort any collection implementing the java.util.List interface based on a given Comparator. A Comparator implementation requires two methods:

int compare(Object o1, Object o2): Compares two objects and returns the result as an int (zero if equal, negative value if the first is less than the second, positive value if the first is more than the second).

boolean equals(Object obj): Returns true if the given object is equal to this Comparator.

Figure 18.4 JTable with ascending and descending sorting of all columns.

<<file figure18-4.gif>>

The Code: StocksTable.java

see \Chapter18\4

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.*;

public class StocksTable extends JFrame

{

  // Unchanged code from section 18.4

  public StocksTable() {

    // Unchanged code from section 18.4

    JTableHeader header = m_table.getTableHeader();

    header.setUpdateTableInRealTime(true);

    header.addMouseListener(m_data.new ColumnListener(m_table));

    header.setReorderingAllowed(true);

    // Unchanged code from section 18.4

  }

  public static void main(String argv[]) {

    new StocksTable();

  }

}

// Unchanged code from section 18.4

class StockTableData extends AbstractTableModel

{

  // Unchanged code from section 18.2

  protected SimpleDateFormat m_frm;

  protected Vector m_vector;

  protected Date   m_date;

  protected int m_sortCol = 0;

  protected boolean m_sortAsc = true;

  public StockTableData() {

    m_frm = new SimpleDateFormat("MM/dd/yyyy");

    m_vector = new Vector();

    setDefaultData();

  }

  public void setDefaultData() {

    // Unchanged code from section 18.4

    Collections.sort(m_vector, new

      StockComparator(m_sortCol, m_sortAsc));

  }

  // Unchanged code from section 18.4

  public String getColumnName(int column) {

    String str = m_columns[column].m_title;

    if (column==m_sortCol)

      str += m_sortAsc ? ">>" : " <<";

    return str;

  }

  // Unchanged code from section 18.4

  class ColumnListener extends MouseAdapter

  {

    protected JTable m_table;

    public ColumnListener(JTable table) {

      m_table = table;

    }

    public void mouseClicked(MouseEvent e) {

      TableColumnModel colModel = m_table.getColumnModel();

      int columnModelIndex = colModel.getColumnIndexAtX(e.getX());

      int modelIndex = colModel.getColumn(columnModelIndex).getModelIndex();

      if (modelIndex < 0)

        return;

      if (m_sortCol==modelIndex)

        m_sortAsc = !m_sortAsc;

      else

        m_sortCol = modelIndex;

      for (int i=0; i < m_columns.length; i++) {

        TableColumn column = colModel.getColumn(i);

        column.setHeaderValue(getColumnName(column.getModelIndex()));    

      }

      m_table.getTableHeader().repaint(); 

      Collections.sort(m_vector, new

        StockComparator(modelIndex, m_sortAsc));

      m_table.tableChanged(

        new TableModelEvent(StockTableData.this));

      m_table.repaint(); 

    }

  }

}

class StockComparator implements Comparator

{

  protected int     m_sortCol;

  protected boolean m_sortAsc;

  public StockComparator(int sortCol, boolean sortAsc) {

    m_sortCol = sortCol;

    m_sortAsc = sortAsc;

  }

  public int compare(Object o1, Object o2) {

    if(!(o1 instanceof StockData) || !(o2 instanceof StockData))

      return 0;

    StockData s1 = (StockData)o1;

    StockData s2 = (StockData)o2;

    int result = 0;

    double d1, d2;

    switch (m_sortCol) {

      case 0:    // symbol

        String str1 = (String)s1.m_symbol.m_data;

        String str2 = (String)s2.m_symbol.m_data;

        result = str1.compareTo(str2);

        break;

      case 1:    // name

        result = s1.m_name.compareTo(s2.m_name);

        break;

      case 2:    // last

        d1 = s1.m_last.doubleValue();

        d2 = s2.m_last.doubleValue();

        result = d1<d2 ? -1 : (d1>d2 ? 1 : 0);

        break;

      case 3:    // open

        d1 = s1.m_open.doubleValue();

        d2 = s2.m_open.doubleValue();

        result = d1<d2 ? -1 : (d1>d2 ? 1 : 0);

        break;

      case 4:    // change

        d1 = ((Fraction)s1.m_change.m_data).doubleValue();

        d2 = ((Fraction)s2.m_change.m_data).doubleValue();

        result = d1<d2 ? -1 : (d1>d2 ? 1 : 0);

        break;

      case 5:    // change %

        d1 = ((Double)s1.m_changePr.m_data).doubleValue();

        d2 = ((Double)s2.m_changePr.m_data).doubleValue();

        result = d1<d2 ? -1 : (d1>d2 ? 1 : 0);

        break;

      case 6:    // volume

        long l1 = s1.m_volume.longValue();

        long l2 = s2.m_volume.longValue();

        result = l1<l2 ? -1 : (l1>l2 ? 1 : 0);

        break;

    }

    if (!m_sortAsc)

      result = -result;

    return result;

  }

  public boolean equals(Object obj) {

    if (obj instanceof StockComparator) {

      StockComparator compObj = (StockComparator)obj;

      return (compObj.m_sortCol==m_sortCol) &&

        (compObj.m_sortAsc==m_sortAsc);

    }

    return false;

  }

}

Understanding the Code

Class StocksTable

In the StocksTable constructor we set the updateTableInRealTime property to show column contents while columns are dragged, and we add an instance of the ColumnListener class (see below) as a mouse listener to the table's header.

Class StockTableData

Here we declare two new instance variables: int m_sortCol to hold the index of the current column chosen for sorting, and boolean m_sortAsc, which is true when sorting in ascending order, and false when sorting in descending order. These variables determine the initial sorting order. To be consistent we sort our table initially by calling the Collections.sort() method in our setDefaultData() method (which is called from the StockTableData constructor).

We also add a special marker for the sorting column's header: '>>' for ascending and '<<' for descending sorting. This changes the way we retrieve a column's name, which no longer is a constant value:

  public String getColumnName(int column) {

    String str = m_columns[column].m_title;

    if (column==m_sortCol)

      str += m_sortAsc ? " >>" : " <<";

    return str;

  }

Class StockTableData.ColumnListener

Because this class interacts heavily with our table data, it is implemented as an inner class in StockTableData. ColumnListener takes a reference to a JTable in its constructor and stores that reference in its m_table instance variable.

The mouseClicked() method is invoked when the user clicks on a header. First it determines the index of the TableColumn clicked based on the coordinate of the click. If for any reason the returned index is negative (i.e. the column cannot be determined) the method cannot continue and we return. Otherwise, we check whether this index corresponds to the column which already has been selected for sorting. If so, we invert the m_sortCol flag to reverse the sorting order. If the index corresponds to newly selected column we store the new sorting index in the m_sortCol variable.

Then we refresh the header names by iterating through the TableColumns and assinging them a name corresponding to the column they represent in the TableModel. To do this we pass each TableColumn's modelIndex property to our getColumnName() method (see above). Finally our table data is re-sorted by calling the Collections.sort() method and passing in a new StockComparator object. We then refresh the table by calling tableChanged() and repaint().

Class StockComparator

This class implements the rule of comparison for two objects, which in our case are StockDatas. Instances of the StockComparator class are passed to the Collections.sort() method to perform data sorting.

Two instance variables are defined:

int m_sortCol represents the index of the column which performs the comparison

boolean m_sortAsc is true for ascending sorting and false for descending.

The StockComparator constructor takes  two  parameters and stores them in these instance variables.

The compare() method takes two objects to be compared and returns an integer value according to the rules determined in the Comparator interface:

0 if object 1 equals 2

A positive number if object 1 is greater than object 2,

A negative number if object 1 is less than object 2.

Since we are dealing only with StockData objects, first we cast both objects and return 0 if this cast isn't possible. The next issue is to define what it means when one StockData objects is greater, equal, or less than another. This is done in a switch-case structure, which, depending on the index of the comparison column, extracts two fields and forms an integer result of the comparison. When the switch-case structure finishes, we know the result of an ascending comparison. For descending comparison we simply need to invert the sign of the result.

The equals() method takes another Comparator instance as parameter and returns true if that parameter represents the same Comparator. We determine this by comparing Comparator instance variables: m_sortCol and m_sortAsc.

Running the Code

Figure 18.4 shows StocksTable sorted by decreasing "Change %." Click different column headers and note that resorting occurs as expected. Click the same column header twice and note that sorting order flips from ascending to descending and vice versa. Also note that the currently selected sorting column header is marked by the '>>' or '<<' symbol. This sorting functionality is very useful. Particularly, for stock market data we can instantly determine which stocks have the highest price fluctuations or the most heavy trade.

UI Guideline : Sort by header selection idiom Introducing table sorting using the column headers is introducing another design idiom to the User Interface. This design idiom is becoming widely accepted and widely used in many applications. It is a useful and powerful technique which you can introduce when sorting table data is a requirement. The technique is not intuitive and their is little visual affordance to suggest that clicking a column header will have any effect. So consider that the introduction of this technique may require additional User training.



[ Return to Swing (Book) ]


Top 10 read Java Articles
 Get free "1000 Java Tips eBook"

 Java Calendar and Date: good to know facts and code examples

 Array vs ArrayList vs LinkedList vs Vector: an excellent overview and examples

 How can I convert any Java Object into byte array? And byte array to file object

 The Java Lesson 1: What is Java?

 How do I compare two dates and times, date between dates, time between times and

 Maven vs Ant or Ant vs Maven?

 How to open, read, write, close file(s) in Java? Examples on move, rename and de

 Java Array

 Java: JLabel font and color


[ More in News Section ]
Java Lessons

The Java Lesson 1:
What is Java?
The Java Lesson 2:
Anatomy of a simple Java program
The Java Lesson 3:
Identifiers and primitive data types
The Java Lesson 4:
Variables, constants, and literals
The Java Lesson 5:
Arithmetic operations, conversions, and casts
The Java Lesson 6:
Boolean expressions and operations
The Java Lesson 7:
Bitwise operations
The Java Lesson 8:
Flow control with if and else
The Java Lesson 9:
switch statements
The Java Lesson 10:
for, while, and do-while statements
The Java Lesson 11:
Using break and continue
The Java Lesson 12:
Class methods and how they are called
The Java Lesson 13:
Using the Math class
The Java Lesson 14:
Creating and calling custom class methods
The Java Lesson 15:
Overloading class methods
The Java Lesson 16:
An introduction to objects and object references
The Java Lesson 17:
The String class
The Java Lesson 18:
The StringBuffer class
The Java Lesson 19:
Initializing and processing arrays of primitives
The Java Lesson 20:
Initializing and processing arrays of objects
The Java Lesson 23:
Inheritance and overriding inherited methods
The Java Lesson 24:
abstract classes and polymorphism
The Java Lesson 25:
Interfaces, instanceof, and object conversion and casting
The Java Lesson 26:
Introduction to graphical programming and the java.awt packa
The Java Lesson 27:
The Component class
The Java Lesson 28:
Containers and simple layout managers
The Java Lesson 29:
The Color and Font classes
The Java Lesson 30:
Drawing geometric shapes
The Java Lesson 31:
Choice, List, and Checkbox controls
The Java Lesson 32:
Using the Scrollbar graphical control
The Java Lesson 33:
Menus and submenus
The Java Lesson 34:
An introduction to applets and the Applet class
The Java Lesson 35:
Essential HTML to launch an applet and pass it parameters
The Java Lesson 36:
Mouse event processing
Java Lesson 37:
Menus and submenus
Java Lesson 38:
The WindowListener interface and the WindowAdapter class
Java Lesson 39:
An introduction to GridBagLayout
Java Lesson 40:
An introduction to the Java Collections API
Java Lesson 41:
Exception handling with try, catch, and finally blocks
Java Lesson 42:
Claiming and throwing exceptions
Java Lesson 43:
Multithreading, the Thread class, and the Runnable interface
Java Lesson 44:
An introduction to I/O and the File and FileDialog classes
Java Lesson 45:
Low-level and high-level stream classes
Java Lesson 46:
Using the RandomAccessFile class
Java Lessons by
Joh Huhtala: Update

Latest articles
 Java Profiler JProbe to Resolve Performance Problems Faster

 SSL with GlassFish v2, page 5

 SSL with GlassFish v2, page 4

 SSL with GlassFish v2, page 3

 SSL with GlassFish v2, page 2

 The Java Lesson 2: Anatomy of a simple Java program, page 2

 New site about Java for robots and robotics: both software and hardware.

 Exceptions -III: What's an exception and why do I care?

 Exceptions -II: What's an exception and why do I care?

 Exceptions: What's an exception and why do I care?

 Double your Java code quality in 10 minutes, here is receipt

 Murach's Java Servlets and JSP

 How to get ascii code from a char in Java?

 Can we just try without catch? Yes!

 Make Tomcat page load faster

 Make your Tomcat More secure - limit network address for certain IP addresses

 New Java book online starts now here...

 Implementing RESTful Web Services in Java

 Firefox trimming from 1 GB to 40 Mb with many tabs opened

 SSL with GlassFish v2

 My request to replublish Tech Tips

 Search JavaFAQ.nu site here

 New Advanced Installer for Java 6.0 brings XML updates and imports 3rd party MSI

 EJB programming restrictions

 Maven vs Ant or Ant vs Maven?

 Why Java does not use default value which it should?

 How to unsign signed bytes in Java - your guide is here

 The Java Lesson 3: Identifiers and primitive data types. Page 2

 The Java Lesson 7: Bitwise operations with good examples, click here! Page 4

 The Java Lesson 7: Bitwise operations with good examples, click here! Page 3


[ More in News Section ]


Home Code Examples Java Forum All Java Tips Books Submit News, Code... Search... Offshore Software Tech Doodling

RSS feed Java FAQ RSS feed Java FAQ News     

    RSS feed Java Forums RSS feed Java Forums

All logos and trademarks in this site are property of their respective owner. The comments are property of their posters, all the rest 1999-2006 by Java FAQs Daily Tips.

Interactive software released under GNU GPL, Code Credits, Privacy Policy