Java/Swing JFC/Table Model

Материал из Java эксперт
Перейти к: навигация, поиск

Содержание

AbstractTableModel backed by Hashtable

    
/*
Definitive Guide to Swing for Java 2, Second Edition
By John Zukowski     
ISBN: 1-893115-78-X
Publisher: APress
*/
import java.awt.BorderLayout;
import java.awt.Point;
import java.util.Hashtable;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableModel;
public class SparseTest {
  public static void main(String args[]) {
    JFrame frame = new JFrame("Sparse Test");
    String headers[] = { "English", "Japanese" };
    TableModel model = new SparseTableModel(10, headers);
    JTable table = new JTable(model);
    model.setValueAt("one", 0, 0);
    model.setValueAt("ten", 9, 0);
    model.setValueAt("roku - \u516D", 5, 1);
    model.setValueAt("hachi - \u516B", 8, 1);
    JScrollPane scrollPane = new JScrollPane(table);
    frame.getContentPane().add(scrollPane, BorderLayout.CENTER);
    frame.setSize(300, 150);
    frame.setVisible(true);
  }
}
class SparseTableModel extends AbstractTableModel {
  private Hashtable lookup;
  private final int rows;
  private final int columns;
  private final String headers[];
  public SparseTableModel(int rows, String columnHeaders[]) {
    if ((rows < 0) || (columnHeaders == null)) {
      throw new IllegalArgumentException(
          "Invalid row count/columnHeaders");
    }
    this.rows = rows;
    this.columns = columnHeaders.length;
    headers = columnHeaders;
    lookup = new Hashtable();
  }
  public int getColumnCount() {
    return columns;
  }
  public int getRowCount() {
    return rows;
  }
  public String getColumnName(int column) {
    return headers[column];
  }
  public Object getValueAt(int row, int column) {
    return lookup.get(new Point(row, column));
  }
  public void setValueAt(Object value, int row, int column) {
    if ((rows < 0) || (columns < 0)) {
      throw new IllegalArgumentException("Invalid row/column setting");
    }
    if ((row < rows) && (column < columns)) {
      lookup.put(new Point(row, column), value);
    }
  }
}





Add a column without affecting existing columns

   
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
public class Main {
  public static void main(String[] argv) throws Exception {
    DefaultTableModel model = new DefaultTableModel();
    JTable table = new JTable(model);
    model = (DefaultTableModel) table.getModel();
    TableColumn col = new TableColumn(model.getColumnCount());
    // Ensure that auto-create is off
    if (table.getAutoCreateColumnsFromModel()) {
      throw new IllegalStateException();
    }
    col.setHeaderValue("Col3");
    table.addColumn(col);
    model.addColumn("Col3",  new Object[] { "v3" });
  }
}





Add a column with values.

   
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
public class Main {
  public static void main(String[] argv) throws Exception {
    DefaultTableModel model = new DefaultTableModel();
    JTable table = new JTable(model);
    // Add a column with values.
    model.addColumn("Col2", new Object[] { "v2" });
  }
}





A JTable class using default table models and a convenience constructor

    
//A test of the JTable class using default table models and a convenience
//constructor. Resizing and selection defaults are altered.
//
import java.awt.BorderLayout;
import java.io.File;
import java.util.Date;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
public class TableFeature extends JFrame {
  String titles[] = new String[] { "Directory?", "File Name", "Read?",
      "Write?", "Size", "Last Modified" };
  public TableFeature() {
    super("Simple JTable Test");
    setSize(300, 200);
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    File pwd = new File(".");
    Object[][] stats = getFileStats(pwd);
    JTable jt = new JTable(stats, titles);
    jt.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
    jt.setColumnSelectionAllowed(true);
    JScrollPane jsp = new JScrollPane(jt);
    getContentPane().add(jsp, BorderLayout.CENTER);
  }
  public Object[][] getFileStats(File dir) {
    String files[] = dir.list();
    Object[][] results = new Object[files.length][titles.length];
    for (int i = 0; i < files.length; i++) {
      File tmp = new File(files[i]);
      results[i][0] = new Boolean(tmp.isDirectory());
      results[i][1] = tmp.getName();
      results[i][2] = new Boolean(tmp.canRead());
      results[i][3] = new Boolean(tmp.canWrite());
      results[i][4] = new Long(tmp.length());
      results[i][5] = new Date(tmp.lastModified());
    }
    return results;
  }
  public static void main(String args[]) {
    TableFeature tf = new TableFeature();
    tf.setVisible(true);
  }
}





Append a row to a table through DefaultTableModel at specified row

   
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
public class Main {
  public static void main(String[] argv) throws Exception {
    DefaultTableModel model = new DefaultTableModel();
    JTable table = new JTable(model);
    model.addColumn("Col1");
    model.addColumn("Col2");
    // Create the first row
    model.insertRow(0, new Object[] { "r1" });
    
    // Append a row
    model.insertRow(model.getRowCount(), new Object[] { "r5" });
    
    JFrame f = new JFrame();
    f.setSize(300, 300);
    f.add(new JScrollPane(table));
    f.setVisible(true);
  }
}





Appending a Column to a JTable Component using DefaultTableModel

   
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
public class Main {
  public static void main(String[] argv) throws Exception {
    DefaultTableModel model = new DefaultTableModel();
    JTable table = new JTable(model);
    model.addColumn("Col1");
  }
}





A simple extension of JTable that supports the use of a SortableTableModel.

  
/* 
 * JCommon : a free general purpose class library for the Java(tm) platform
 * 
 *
 * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
 * 
 * Project Info:  http://www.jfree.org/jcommon/index.html
 *
 * This library is free software; you can redistribute it and/or modify it 
 * under the terms of the GNU Lesser General Public License as published by 
 * the Free Software Foundation; either version 2.1 of the License, or 
 * (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but 
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
 * License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
 * USA.  
 *
 * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 
 * in the United States and other countries.]
 * 
 * ------------------
 * SortableTable.java
 * ------------------
 * (C) Copyright 2000-2004, by Object Refinery Limited.
 *
 * Original Author:  David Gilbert (for Object Refinery Limited);
 * Contributor(s):   -;
 *
 * $Id: SortableTable.java,v 1.5 2005/11/16 15:58:41 taqua Exp $
 *
 * Changes (from 26-Oct-2001)
 * --------------------------
 * 26-Oct-2001 : Changed package to com.jrefinery.ui.*;
 * 14-Oct-2002 : Fixed errors reported by Checkstyle (DG);
 *
 */

import java.awt.Color;
import java.awt.ruponent;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumnModel;
/**
 * A simple extension of JTable that supports the use of a SortableTableModel.
 *
 * @author David Gilbert
 */
public class SortableTable extends JTable {
    /** A listener for sorting. */
    private SortableTableHeaderListener headerListener;
    /**
     * Standard constructor - builds a table for the specified model.
     *
     * @param model  the data.
     */
    public SortableTable(final SortableTableModel model) {
        super(model);
        final SortButtonRenderer renderer = new SortButtonRenderer();
        final TableColumnModel cm = getColumnModel();
        for (int i = 0; i < cm.getColumnCount(); i++) {
            cm.getColumn(i).setHeaderRenderer(renderer);
        }
        final JTableHeader header = getTableHeader();
        this.headerListener = new SortableTableHeaderListener(model, renderer);
        header.addMouseListener(this.headerListener);
        header.addMouseMotionListener(this.headerListener);
        model.sortByColumn(0, true);
    }
    /**
     * Changes the model for the table.  Takes care of updating the header listener at the
     * same time.
     *
     * @param model  the table model.
     *
     */
    public void setSortableModel(final SortableTableModel model) {
        super.setModel(model);
        this.headerListener.setTableModel(model);
        final SortButtonRenderer renderer = new SortButtonRenderer();
        final TableColumnModel cm = getColumnModel();
        for (int i = 0; i < cm.getColumnCount(); i++) {
            cm.getColumn(i).setHeaderRenderer(renderer);
        }
        model.sortByColumn(0, true);
    }
}
/* 
 * JCommon : a free general purpose class library for the Java(tm) platform
 * 
 *
 * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
 * 
 * Project Info:  http://www.jfree.org/jcommon/index.html
 *
 * This library is free software; you can redistribute it and/or modify it 
 * under the terms of the GNU Lesser General Public License as published by 
 * the Free Software Foundation; either version 2.1 of the License, or 
 * (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but 
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
 * License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
 * USA.  
 *
 * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 
 * in the United States and other countries.]
 * 
 * --------------------------------
 * SortableTableHeaderListener.java
 * --------------------------------
 * (C) Copyright 2000-2004, by Nabuo Tamemasa and Contributors.
 *
 * Original Author:  Nabuo Tamemasa;
 * Contributor(s):   David Gilbert (for Object Refinery Limited);
 *
 * $Id: SortableTableHeaderListener.java,v 1.5 2007/11/02 17:50:36 taqua Exp $
 *
 * Changes (from 26-Oct-2001)
 * --------------------------
 * 26-Oct-2001 : Changed package to com.jrefinery.ui.*;
 * 14-Oct-2002 : Fixed errors reported by Checkstyle (DG);
 *
 */

/**
 * Captures mouse clicks on a table header, with the intention of triggering a sort.  Adapted from
 * code by Nabuo Tamemasa posted on http://www.codeguru.ru.
 *
 * @author Nabuo Tamemasa
 */
class SortableTableHeaderListener implements MouseListener, MouseMotionListener {
    /** A reference to the table model. */
    private SortableTableModel model;
    /** The header renderer. */
    private SortButtonRenderer renderer;
    /** The index of the column that is sorted - used to determine the state of the renderer. */
    private int sortColumnIndex;
    /**
     * Standard constructor.
     *
     * @param model  the model.
     * @param renderer  the renderer.
     */
    public SortableTableHeaderListener(final SortableTableModel model, 
                                       final SortButtonRenderer renderer) {
        this.model = model;
        this.renderer = renderer;
    }
    /**
     * Sets the table model for the listener.
     *
     * @param model  the model.
     */
    public void setTableModel(final SortableTableModel model) {
        this.model = model;
    }
    /**
     * Handle a mouse press event - if the user is NOT resizing a column and NOT dragging a column
     * then give visual feedback that the column header has been pressed.
     *
     * @param e  the mouse event.
     */
    public void mousePressed(final MouseEvent e) {
        final JTableHeader header = (JTableHeader) e.getComponent();
        if (header.getResizingColumn() == null) {  // resizing takes precedence over sorting
            if (header.getDraggedDistance() < 1) {   // dragging also takes precedence over sorting
                final int columnIndex = header.columnAtPoint(e.getPoint());
                final int modelColumnIndex 
                    = header.getTable().convertColumnIndexToModel(columnIndex);
                if (this.model.isSortable(modelColumnIndex)) {
                    this.sortColumnIndex = header.getTable().convertColumnIndexToModel(columnIndex);
                    this.renderer.setPressedColumn(this.sortColumnIndex);
                    header.repaint();
                    if (header.getTable().isEditing()) {
                        header.getTable().getCellEditor().stopCellEditing();
                    }
                }
                else {
                    this.sortColumnIndex = -1;
                }
            }
        }
    }
    /**
     * If the user is dragging or resizing, then we clear the sort column.
     *
     * @param e  the mouse event.
     */
    public void mouseDragged(final MouseEvent e) {
        final JTableHeader header = (JTableHeader) e.getComponent();
        if ((header.getDraggedDistance() > 0) || (header.getResizingColumn() != null)) {
            this.renderer.setPressedColumn(-1);
            this.sortColumnIndex = -1;
        }
    }
    /**
     * This event is ignored (not required).
     *
     * @param e  the mouse event.
     */
    public void mouseEntered(final MouseEvent e) {
        // not required
    }
    /**
     * This event is ignored (not required).
     *
     * @param e  the mouse event.
     */
    public void mouseClicked(final MouseEvent e) {
        // not required
    }
    /**
     * This event is ignored (not required).
     *
     * @param e  the mouse event.
     */
    public void mouseMoved(final MouseEvent e) {
        // not required
    }
    /**
     * This event is ignored (not required).
     *
     * @param e  the mouse event.
     */
    public void mouseExited(final MouseEvent e) {
        // not required
    }
    /**
     * When the user releases the mouse button, we attempt to sort the table.
     *
     * @param e  the mouse event.
     */
    public void mouseReleased(final MouseEvent e) {
        final JTableHeader header = (JTableHeader) e.getComponent();
        if (header.getResizingColumn() == null) {  // resizing takes precedence over sorting
            if (this.sortColumnIndex != -1) {
                final SortableTableModel model = (SortableTableModel) header.getTable().getModel();
                final boolean ascending = !model.isAscending();
                model.setAscending(ascending);
                model.sortByColumn(this.sortColumnIndex, ascending);
                this.renderer.setPressedColumn(-1);       // clear
                header.repaint();
            }
        }
    }
}
/* 
 * JCommon : a free general purpose class library for the Java(tm) platform
 * 
 *
 * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
 *
 * Project Info:  http://www.jfree.org/jcommon/index.html
 *
 * This library is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
 * License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
 * USA.
 *
 * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
 * in the United States and other countries.]
 *
 * -----------------------
 * SortableTableModel.java
 * -----------------------
 * (C) Copyright 2000-2005, by Object Refinery Limited;
 *
 * Original Author:  David Gilbert (for Object Refinery Limited);
 * Contributor(s):   -;
 *
 * $Id: SortableTableModel.java,v 1.6 2008/09/10 09:26:11 mungady Exp $
 *
 * Changes (from 26-Oct-2001)
 * --------------------------
 * 26-Oct-2001 : Changed package to com.jrefinery.ui.* (DG);
 * 20-Nov-2001 : Made constructor protected (DG);
 * 14-Oct-2002 : Fixed errors reported by Checkstyle (DG);
 *
 */


/**
 * The base class for a sortable table model.
 *
 * @author David Gilbert
 */
abstract class SortableTableModel extends AbstractTableModel {
    /** The column on which the data is sorted (-1 for no sorting). */
    private int sortingColumn;
    /** Indicates ascending (true) or descending (false) order. */
    private boolean ascending;
    /**
     * Constructs a sortable table model.
     */
    public SortableTableModel() {
        this.sortingColumn = -1;
        this.ascending = true;
    }
    /**
     * Returns the index of the sorting column, or -1 if the data is not sorted
     * on any column.
     *
     * @return the column used for sorting.
     */
    public int getSortingColumn() {
        return this.sortingColumn;
    }
    /**
     * Returns <code>true</code> if the data is sorted in ascending order, and
     * <code>false</code> otherwise.
     *
     * @return <code>true</code> if the data is sorted in ascending order, and
     *         <code>false</code> otherwise.
     */
    public boolean isAscending() {
        return this.ascending;
    }
    /**
     * Sets the flag that determines whether the sort order is ascending or
     * descending.
     *
     * @param flag  the flag.
     */
    public void setAscending(final boolean flag) {
        this.ascending = flag;
    }
    /**
     * Sorts the table.
     *
     * @param column  the column to sort on (zero-based index).
     * @param ascending  a flag to indicate ascending order or descending order.
     */
    public void sortByColumn(final int column, final boolean ascending) {
        if (isSortable(column)) {
            this.sortingColumn = column;
        }
    }
    /**
     * Returns a flag indicating whether or not a column is sortable.
     *
     * @param column  the column (zero-based index).
     *
     * @return boolean.
     */
    public boolean isSortable(final int column) {
        return false;
    }
}
/* 
 * JCommon : a free general purpose class library for the Java(tm) platform
 * 
 * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
 *
 * Project Info:  http://www.jfree.org/jcommon/index.html
 *
 * This library is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
 * License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
 * USA.
 *
 * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
 * in the United States and other countries.]
 *
 * -----------------------
 * SortButtonRenderer.java
 * -----------------------
 * (C) Copyright 2000-2004, by Nobuo Tamemasa and Contributors.
 *
 * Original Author:  Nobuo Tamemasa;
 * Contributor(s):   David Gilbert (for Object Refinery Limited);
 *                   Gareth Davis;
 *
 * $Id: SortButtonRenderer.java,v 1.7 2008/09/10 09:26:11 mungady Exp $
 *
 * Changes (from 26-Oct-2001)
 * --------------------------
 * 26-Oct-2001 : Changed package to com.jrefinery.ui.* (DG);
 * 26-Jun-2002 : Removed unnecessary import (DG);
 * 14-Oct-2002 : Fixed errors reported by Checkstyle (DG);
 *
 */

/**
 * A table cell renderer for table headings - uses one of three JButton instances to indicate the
 * sort order for the table column.
 * <P>
 * This class (and also BevelArrowIcon) is adapted from original code by Nobuo Tamemasa (version
 * 1.0, 26-Feb-1999) posted on www.codeguru.ru.
 *
 * @author David Gilbert
 */
class SortButtonRenderer implements TableCellRenderer {
    /**
     * Useful constant indicating NO sorting.
     */
    public static final int NONE = 0;
    /**
     * Useful constant indicating ASCENDING (that is, arrow pointing down) sorting in the table.
     */
    public static final int DOWN = 1;
    /**
     * Useful constant indicating DESCENDING (that is, arrow pointing up) sorting in the table.
     */
    public static final int UP = 2;
    /**
     * The current pressed column (-1 for no column).
     */
    private int pressedColumn = -1;
    /**
     * The three buttons that are used to render the table header cells.
     */
    private JButton normalButton;
    /**
     * The three buttons that are used to render the table header cells.
     */
    private JButton ascendingButton;
    /**
     * The three buttons that are used to render the table header cells.
     */
    private JButton descendingButton;
    /**
     * Used to allow the class to work out whether to use the buttuns
     * or labels. Labels are required when using the aqua look and feel cos the
     * buttons won"t fit.
     */
    private boolean useLabels;
    /**
     * The normal label (only used with MacOSX).
     */
    private JLabel normalLabel;
    /**
     * The ascending label (only used with MacOSX).
     */
    private JLabel ascendingLabel;
    /**
     * The descending label (only used with MacOSX).
     */
    private JLabel descendingLabel;
    /**
     * Creates a new button renderer.
     */
    public SortButtonRenderer() {
        this.pressedColumn = -1;
        this.useLabels = UIManager.getLookAndFeel().getID().equals("Aqua");
        final Border border = UIManager.getBorder("TableHeader.cellBorder");
        if (this.useLabels) {
            this.normalLabel = new JLabel();
            this.normalLabel.setHorizontalAlignment(SwingConstants.LEADING);
            this.ascendingLabel = new JLabel();
            this.ascendingLabel.setHorizontalAlignment(SwingConstants.LEADING);
            this.ascendingLabel.setHorizontalTextPosition(SwingConstants.LEFT);
            this.ascendingLabel.setIcon(new BevelArrowIcon(BevelArrowIcon.DOWN, false, false));
            this.descendingLabel = new JLabel();
            this.descendingLabel.setHorizontalAlignment(SwingConstants.LEADING);
            this.descendingLabel.setHorizontalTextPosition(SwingConstants.LEFT);
            this.descendingLabel.setIcon(new BevelArrowIcon(BevelArrowIcon.UP, false, false));
            this.normalLabel.setBorder(border);
            this.ascendingLabel.setBorder(border);
            this.descendingLabel.setBorder(border);
        }
        else {
            this.normalButton = new JButton();
            this.normalButton.setMargin(new Insets(0, 0, 0, 0));
            this.normalButton.setHorizontalAlignment(SwingConstants.LEADING);
            this.ascendingButton = new JButton();
            this.ascendingButton.setMargin(new Insets(0, 0, 0, 0));
            this.ascendingButton.setHorizontalAlignment(SwingConstants.LEADING);
            this.ascendingButton.setHorizontalTextPosition(SwingConstants.LEFT);
            this.ascendingButton.setIcon(new BevelArrowIcon(BevelArrowIcon.DOWN, false, false));
            this.ascendingButton.setPressedIcon(new BevelArrowIcon(BevelArrowIcon.DOWN, false, true));
            this.descendingButton = new JButton();
            this.descendingButton.setMargin(new Insets(0, 0, 0, 0));
            this.descendingButton.setHorizontalAlignment(SwingConstants.LEADING);
            this.descendingButton.setHorizontalTextPosition(SwingConstants.LEFT);
            this.descendingButton.setIcon(new BevelArrowIcon(BevelArrowIcon.UP, false, false));
            this.descendingButton.setPressedIcon(new BevelArrowIcon(BevelArrowIcon.UP, false, true));
            this.normalButton.setBorder(border);
            this.ascendingButton.setBorder(border);
            this.descendingButton.setBorder(border);
        }
    }
    /**
     * Returns the renderer component.
     *
     * @param table      the table.
     * @param value      the value.
     * @param isSelected selected?
     * @param hasFocus   focussed?
     * @param row        the row.
     * @param column     the column.
     * @return the renderer.
     */
    public Component getTableCellRendererComponent(final JTable table,
                                                   final Object value,
                                                   final boolean isSelected,
                                                   final boolean hasFocus,
                                                   final int row, final int column) {
        if (table == null) {
            throw new NullPointerException("Table must not be null.");
        }
        final JComponent component;
        final SortableTableModel model = (SortableTableModel) table.getModel();
        final int cc = table.convertColumnIndexToModel(column);
        final boolean isSorting = (model.getSortingColumn() == cc);
        final boolean isAscending = model.isAscending();
        final JTableHeader header = table.getTableHeader();
        final boolean isPressed = (cc == this.pressedColumn);
        if (this.useLabels) {
            final JLabel label = getRendererLabel(isSorting, isAscending);
            label.setText((value == null) ? "" : value.toString());
            component = label;
        }
        else {
            final JButton button = getRendererButton(isSorting, isAscending);
            button.setText((value == null) ? "" : value.toString());
            button.getModel().setPressed(isPressed);
            button.getModel().setArmed(isPressed);
            component = button;
        }
        if (header != null) {
            component.setForeground(header.getForeground());
            component.setBackground(header.getBackground());
            component.setFont(header.getFont());
        }
        return component;
    }
    /**
     * Returns the correct button component.
     *
     * @param isSorting whether the render component represents the sort column.
     * @param isAscending whether the model is ascending.
     * @return either the ascending, descending or normal button.
     */
    private JButton getRendererButton(final boolean isSorting, final boolean isAscending) {
        if (isSorting) {
            if (isAscending) {
                return this.ascendingButton;
            }
            else {
                return this.descendingButton;
            }
        }
        else {
            return this.normalButton;
        }
    }
    /**
     * Returns the correct label component.
     *
     * @param isSorting whether the render component represents the sort column.
     * @param isAscending whether the model is ascending.
     * @return either the ascending, descending or normal label.
     */
    private JLabel getRendererLabel(final boolean isSorting, final boolean isAscending) {
        if (isSorting) {
            if (isAscending) {
                return this.ascendingLabel;
            }
            else {
                return this.descendingLabel;
            }
        }
        else {
            return this.normalLabel;
        }
    }
    /**
     * Sets the pressed column.
     *
     * @param column the column.
     */
    public void setPressedColumn(final int column) {
        this.pressedColumn = column;
    }
}
/* 
 * JCommon : a free general purpose class library for the Java(tm) platform
 * 
 *
 * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
 * 
 * Project Info:  http://www.jfree.org/jcommon/index.html
 *
 * This library is free software; you can redistribute it and/or modify it 
 * under the terms of the GNU Lesser General Public License as published by 
 * the Free Software Foundation; either version 2.1 of the License, or 
 * (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but 
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
 * License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
 * USA.  
 *
 * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 
 * in the United States and other countries.]
 * 
 * -------------------
 * BevelArrowIcon.java
 * -------------------
 * (C) Copyright 2000-2004, by Nobuo Tamemasa and Contributors.
 *
 * Original Author:  Nobuo Tamemasa;
 * Contributor(s):   David Gilbert (for Object Refinery Limited);
 *
 * $Id: BevelArrowIcon.java,v 1.5 2007/11/02 17:50:36 taqua Exp $
 *
 * Changes (from 26-Oct-2001)
 * --------------------------
 * 26-Oct-2001 : Changed package to com.jrefinery.ui.*;
 * 13-Oct-2002 : Fixed errors reported by Checkstyle (DG);
 *
 */

/**
 * An arrow icon that can point up or down (usually used to indicate the sort direction in a table).
 * <P>
 * This class (and also SortButtonRenderer) is based on original code by Nobuo Tamemasa (version
 * 1.0, 26-Feb-1999) posted on www.codeguru.ru.
 *
 * @author Nobuo Tamemasa
 */
class BevelArrowIcon implements Icon {
    /** Constant indicating that the arrow is pointing up. */
    public static final int UP = 0;
    /** Constant indicating that the arrow is pointing down. */
    public static final int DOWN = 1;
    /** The default arrow size. */
    private static final int DEFAULT_SIZE = 11;
    /** Edge color 1. */
    private Color edge1;
    /** Edge color 2. */
    private Color edge2;
    /** The fill color for the arrow icon. */
    private Color fill;
    /** The size of the icon. */
    private int size;
    /** The direction that the arrow is pointing (UP or DOWN). */
    private int direction;
    /**
     * Standard constructor - builds an icon with the specified attributes.
     *
     * @param direction .
     * @param isRaisedView .
     * @param isPressedView .
     */
    public BevelArrowIcon(final int direction, 
                          final boolean isRaisedView, 
                          final boolean isPressedView) {
        if (isRaisedView) {
            if (isPressedView) {
                init(UIManager.getColor("controlLtHighlight"),
                     UIManager.getColor("controlDkShadow"),
                     UIManager.getColor("controlShadow"),
                     DEFAULT_SIZE, direction);
            }
            else {
                init(UIManager.getColor("controlHighlight"),
                     UIManager.getColor("controlShadow"),
                     UIManager.getColor("control"),
                     DEFAULT_SIZE, direction);
            }
        }
        else {
            if (isPressedView) {
                init(UIManager.getColor("controlDkShadow"),
                     UIManager.getColor("controlLtHighlight"),
                     UIManager.getColor("controlShadow"),
                     DEFAULT_SIZE, direction);
            }
            else {
                init(UIManager.getColor("controlShadow"),
                     UIManager.getColor("controlHighlight"),
                     UIManager.getColor("control"),
                     DEFAULT_SIZE, direction);
            }
        }
    }
    /**
     * Standard constructor - builds an icon with the specified attributes.
     *
     * @param edge1  the color of edge1.
     * @param edge2  the color of edge2.
     * @param fill  the fill color.
     * @param size  the size of the arrow icon.
     * @param direction  the direction that the arrow points.
     */
    public BevelArrowIcon(final Color edge1, 
                          final Color edge2, 
                          final Color fill, 
                          final int size, 
                          final int direction) {
        init(edge1, edge2, fill, size, direction);
    }
    /**
     * Paints the icon at the specified position.  Supports the Icon interface.
     *
     * @param c .
     * @param g .
     * @param x .
     * @param y .
     */
    public void paintIcon(final Component c, 
                          final Graphics g, 
                          final int x, 
                          final int y) {
        switch (this.direction) {
            case DOWN: drawDownArrow(g, x, y); break;
            case   UP: drawUpArrow(g, x, y);   break;
        }
    }
    /**
     * Returns the width of the icon.  Supports the Icon interface.
     *
     * @return the icon width.
     */
    public int getIconWidth() {
        return this.size;
    }
    /**
     * Returns the height of the icon.  Supports the Icon interface.
     * @return the icon height.
     */
    public int getIconHeight() {
        return this.size;
    }
    /**
     * Initialises the attributes of the arrow icon.
     *
     * @param edge1  the color of edge1.
     * @param edge2  the color of edge2.
     * @param fill  the fill color.
     * @param size  the size of the arrow icon.
     * @param direction  the direction that the arrow points.
     */
    private void init(final Color edge1, 
                      final Color edge2, 
                      final Color fill, 
                      final int size, 
                      final int direction) {
        this.edge1 = edge1;
        this.edge2 = edge2;
        this.fill = fill;
        this.size = size;
        this.direction = direction;
    }
    /**
     * Draws the arrow pointing down.
     *
     * @param g  the graphics device.
     * @param xo  ??
     * @param yo  ??
     */
    private void drawDownArrow(final Graphics g, final int xo, final int yo) {
        g.setColor(this.edge1);
        g.drawLine(xo, yo,   xo + this.size - 1, yo);
        g.drawLine(xo, yo + 1, xo + this.size - 3, yo + 1);
        g.setColor(this.edge2);
        g.drawLine(xo + this.size - 2, yo + 1, xo + this.size - 1, yo + 1);
        int x = xo + 1;
        int y = yo + 2;
        int dx = this.size - 6;
        while (y + 1 < yo + this.size) {
            g.setColor(this.edge1);
            g.drawLine(x, y,   x + 1, y);
            g.drawLine(x, y + 1, x + 1, y + 1);
            if (0 < dx) {
                g.setColor(this.fill);
                g.drawLine(x + 2, y,   x + 1 + dx, y);
                g.drawLine(x + 2, y + 1, x + 1 + dx, y + 1);
            }
            g.setColor(this.edge2);
            g.drawLine(x + dx + 2, y,   x + dx + 3, y);
            g.drawLine(x + dx + 2, y + 1, x + dx + 3, y + 1);
            x += 1;
            y += 2;
            dx -= 2;
        }
        g.setColor(this.edge1);
        g.drawLine(
            xo + (this.size / 2), yo + this.size - 1, xo + (this.size / 2), yo + this.size - 1
        );
    }
    /**
     * Draws the arrow pointing up.
     *
     * @param g  the graphics device.
     * @param xo  ??
     * @param yo  ??
     */
    private void drawUpArrow(final Graphics g, final int xo, final int yo) {
        g.setColor(this.edge1);
        int x = xo + (this.size / 2);
        g.drawLine(x, yo, x, yo);
        x--;
        int y = yo + 1;
        int dx = 0;
        while (y + 3 < yo + this.size) {
            g.setColor(this.edge1);
            g.drawLine(x, y,   x + 1, y);
            g.drawLine(x, y + 1, x + 1, y + 1);
            if (0 < dx) {
                g.setColor(this.fill);
                g.drawLine(x + 2, y,   x + 1 + dx, y);
                g.drawLine(x + 2, y + 1, x + 1 + dx, y + 1);
            }
            g.setColor(this.edge2);
            g.drawLine(x + dx + 2, y,   x + dx + 3, y);
            g.drawLine(x + dx + 2, y + 1, x + dx + 3, y + 1);
            x -= 1;
            y += 2;
            dx += 2;
        }
        g.setColor(this.edge1);
        g.drawLine(xo, yo + this.size - 3,   xo + 1, yo + this.size - 3);
        g.setColor(this.edge2);
        g.drawLine(xo + 2, yo + this.size - 2, xo + this.size - 1, yo + this.size - 2);
        g.drawLine(xo, yo + this.size - 1, xo + this.size, yo + this.size - 1);
    }
}





Bean Property Table Model

    
/*
 * Copyright (C) 2001-2003 Colin Bell
 * colbell@users.sourceforge.net
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.ruparator;
import java.util.Vector;
import javax.swing.table.DefaultTableModel;

public class BeanPropertyTableModel extends DefaultTableModel
{
    private static final long serialVersionUID = 1L;

  private Object _bean;
  private String _nameColumnName = "Namecolumn";
  private String _valueColumnName = "Valuecolumn";
  public BeanPropertyTableModel()
  {
    super();
  }
  public void setBean(Object bean) throws RuntimeException
  {
    _bean = bean;
    refresh();
  }
  public void refresh() throws RuntimeException
  {
    final Vector<Object> columnNames = new Vector<Object>();
    columnNames.add(_nameColumnName);
    columnNames.add(_valueColumnName);
    final Vector<Object> columnData = new Vector<Object>();
    if (_bean != null)
    {
      try
      {
        BeanInfo info = Introspector.getBeanInfo(_bean.getClass(), Introspector.USE_ALL_BEANINFO);
        processBeanInfo(info, columnData);
      }
      catch (Exception ex)
      {
        throw new RuntimeException(ex);
      }
    }
    // Sort the rows by the property name.
    Collections.sort(columnData, new DataSorter());
    setDataVector(columnData, columnNames);
  }
  private void processBeanInfo(BeanInfo info, Vector<Object> columnData)
    throws InvocationTargetException, IllegalAccessException
  {
    BeanInfo[] extra = info.getAdditionalBeanInfo();
    if (extra != null)
    {
      for (int i = 0; i < extra.length; ++i)
      {
        processBeanInfo(extra[i], columnData);
      }
    }
    PropertyDescriptor[] propDesc = info.getPropertyDescriptors();
    for (int i = 0; i < propDesc.length; ++i)
    {
      final String propName = propDesc[i].getName();
      final Method getter = propDesc[i].getReadMethod();
      if (propName != null && getter != null)
      {
        Vector<Object> line = generateLine(propName, _bean, getter);
        if (line != null)
        {
          columnData.add(line);
        }
      }
    }
  }
  /**
   * Generate a line for the passed property.
   *
   * @param propName  Name of the property.
   * @param bean    Bean containg the property.
   * @param getter    The "getter" function to retrieve the
   *            properties value.
   *
   * @return  A <CODE>Vector</CODE> containing the cells for the line in
   *      the table. Element zero the first cell etc. Return
   *      <CODE>null</CODE> if this property is <B>not</B> to be added
   *      to the table.
   */
  protected Vector<Object> generateLine(String propName, Object bean, Method getter)
    throws InvocationTargetException, IllegalAccessException
  {
    final Vector<Object> line = new Vector<Object>();
    line.add(propName);
    line.add(executeGetter(bean, getter));
    return line;
  }
  protected Object executeGetter(Object bean, Method getter)
    throws InvocationTargetException, IllegalAccessException
  {
    return getter.invoke(bean, (Object[])null);
  }
  public void setNameColumnName(String value)
  {
    _nameColumnName = value;
  }
  public void setValueColumnName(String value)
  {
    _valueColumnName = value;
  }
  /**
   * This comparator is compatible with the strange use of lists in this 
   * class.  This classes lists are Vectors with Strings as the first element
   * and any object as the other objects.
   */
  private static final class DataSorter implements Comparator<Object>
  {
    public int compare(Object o1, Object o2)
    {
        Vector<Object> v1 = (Vector<Object>)o1;
        Vector<Object> v2 = (Vector<Object>)o2;
        String lhs = (String)v1.get(0);
        String rhs = (String)v2.get(0);
      return lhs.rupareToIgnoreCase(rhs);
    }
  }
}





Converts a column index in the model to a visible column index

   
import javax.swing.JTable;
import javax.swing.table.TableColumn;
public class Main {
  public static void main(String[] argv) throws Exception {
  }
  public int toView(JTable table, int mColIndex) {
    for (int c = 0; c < table.getColumnCount(); c++) {
      TableColumn col = table.getColumnModel().getColumn(c);
      if (col.getModelIndex() == mColIndex) {
        return c;
      }
    }
    return -1;
  }
}





Converts a visible column index to a column index in the model.

   
import javax.swing.JTable;
public class Main {
  public static void main(String[] argv) {
  }
  public int toModel(JTable table, int vColIndex) {
    if (vColIndex >= table.getColumnCount()) {
      return -1;
    }
    return table.getColumnModel().getColumn(vColIndex).getModelIndex();
  }
}





Copy (clone) the data from the second row

   

import java.util.ArrayList;
import java.util.Vector;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
public class Main {
  public static void main(String[] argv) throws Exception {
    DefaultTableModel model = new DefaultTableModel();
    JTable table = new JTable(model);
    model.addColumn("Col1");
    model.addRow(new Object[] { "r1" });
    model.addRow(new Object[] { "r2" });
    model.addRow(new Object[] { "r3" });
    
    // Get all the table data
    Vector data = model.getDataVector();
    // Copy the second row
    Vector row = (Vector) data.elementAt(1);
    row = (Vector) row.clone();
    
    JFrame f = new JFrame();
    f.setSize(300, 300);
    f.add(new JScrollPane(table));
    f.setVisible(true);
  }
}





Copy data from a table to a list

   
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
public class Main {
  public static void main(String[] argv) throws Exception {
    DefaultTableModel model = new DefaultTableModel();
    JTable table = new JTable(model);
    model.addColumn("Col1");
    model.addRow(new Object[] { "r1" });
    model.addRow(new Object[] { "r2" });
    model.addRow(new Object[] { "r3" });
    
    Vector data = model.getDataVector();
    Vector row = (Vector) data.elementAt(1);
    // Copy the first column
    int mColIndex = 0;
    List colData = new ArrayList(table.getRowCount());
    for (int i = 0; i < table.getRowCount(); i++) {
      row = (Vector) data.elementAt(i);
      colData.add(row.get(mColIndex));
    }
    JFrame f = new JFrame();
    f.setSize(300, 300);
    f.add(new JScrollPane(table));
    f.setVisible(true);
  }
}





Creating simple JTable using AbstractTableModel

   
import java.awt.Dimension;
import java.util.Vector;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
public class Main extends JFrame {
  private JTable m_simpleTable;
  private SimpleTableModel m_simpleTableModel;
  public Main() {
    Vector dummyMacData = new Vector(10, 10);
    dummyMacData.addElement(new Data(new Integer(100), "A", "1","C", "E"));
    dummyMacData.addElement(new Data(new Integer(105), "R", "2","S", "E"));
    m_simpleTableModel = new SimpleTableModel(dummyMacData);
    m_simpleTable = new JTable(m_simpleTableModel);
    JScrollPane scrollPane = new JScrollPane(m_simpleTable);
    getContentPane().add(scrollPane);
  }
  public static void main(String[] arg) {
    Main m = new Main();
    m.setVisible(true);
    m.setSize(new Dimension(600, 300));
    m.validate();
  }
  class SimpleTableModel extends AbstractTableModel {
    public String[] m_colNames = { "A", "B", "C","D", "E" };
    public Class[] m_colTypes = { Integer.class, String.class, String.class, String.class,
        String.class };
    Vector m_macDataVector;
    public SimpleTableModel(Vector macDataVector) {
      super();
      m_macDataVector = macDataVector;
    }
    public int getColumnCount() {
      return m_colNames.length;
    }
    public int getRowCount() {
      return m_macDataVector.size();
    }
    public void setValueAt(Object value, int row, int col) {
      Data macData = (Data) (m_macDataVector.elementAt(row));
      switch (col) {
      case 0:
        macData.setA((Integer) value);
        break;
      case 1:
        macData.setB((String) value);
        break;
      case 2:
        macData.setC((String) value);
        break;
      case 3:
        macData.setD((String) value);
        break;
      case 4:
        macData.setE((String) value);
        break;
      }
    }
    public String getColumnName(int col) {
      return m_colNames[col];
    }
    public Class getColumnClass(int col) {
      return m_colTypes[col];
    }
    public Object getValueAt(int row, int col) {
      Data macData = (Data) (m_macDataVector.elementAt(row));
      switch (col) {
      case 0:
        return macData.getA();
      case 1:
        return macData.getB();
      case 2:
        return macData.getC();
      case 3:
        return macData.getD();
      case 4:
        return macData.getE();
      }
      return new String();
    }
  }
}
class Data {
  private Integer a;
  private String b;
  private String c;
  private String d;
  private String e;
  public Data() {
  }
  public Data(Integer aa, String bb, String cc, String dd, String ee) {
    a = aa;
    b = bb;
    c = cc;
    d = dd;
    e = ee;
  }
  public Integer getA() {
    return a;
  }
  public String getB() {
    return b;
  }
  public String getC() {
    return c;
  }
  public String getD() {
    return d;
  }
  public String getE() {
    return e;
  }
  public void setA(Integer aa) {
    a = aa;
  }
  public void setB(String macName) {
    b = macName;
  }
  public void setC(String cc) {
    c = cc;
  }
  public void setD(String dd) {
    d = dd;
  }
  public void setE(String ee) {
    e = ee;
  }
}





Custom model, POJO and JTable

    
/*
Java Swing, 2nd Edition
By Marc Loy, Robert Eckstein, Dave Wood, James Elliott, Brian Cole
ISBN: 0-596-00408-7
Publisher: O"Reilly 
*/
// MarketTable.java
//An application that display stock market data in a JTable. The table
//uses the MarketDataModel class for its model. MYOSM should be running
//to make the data dynamic.
//
import java.awt.BorderLayout;
import java.util.Date;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
public class MarketTable extends JFrame {
  public MarketTable() {
    super("Dynamic Data Test");
    setSize(300, 200);
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    // Set up our table model with a 5-second polling delay
    MarketDataModel mdm = new MarketDataModel(5);
    // Pick which stocks we want to watch . . .
    mdm.setStocks(new int[] { 0, 1, 2 });
    // And pop up the table
    JTable jt = new JTable(mdm);
    JScrollPane jsp = new JScrollPane(jt);
    getContentPane().add(jsp, BorderLayout.CENTER);
  }
  public static void main(String args[]) {
    MarketTable mt = new MarketTable();
    mt.setVisible(true);
  }
}
//MarketDataModel.java
//A custom table model for use with the MYOSM enviornment.
//
class MarketDataModel extends AbstractTableModel implements Runnable {
  Thread runner;
  MYOSM market;
  int delay;
  public MarketDataModel(int initialDelay) {
    market = new MYOSM();
    delay = initialDelay * 1000;
    Thread runner = new Thread(this);
    runner.start();
  }
  Stock[] stocks = new Stock[0];
  int[] stockIndices = new int[0];
  String[] headers = { "Symbol", "Price", "Change", "Last updated" };
  public int getRowCount() {
    return stocks.length;
  }
  public int getColumnCount() {
    return headers.length;
  }
  public String getColumnName(int c) {
    return headers[c];
  }
  public Object getValueAt(int r, int c) {
    switch (c) {
    case 0:
      return stocks[r].symbol;
    case 1:
      return new Double(stocks[r].price);
    case 2:
      return new Double(stocks[r].delta);
    case 3:
      return stocks[r].lastUpdate;
    }
    throw new IllegalArgumentException("Bad cell (" + r + ", " + c + ")");
  }
  public void setDelay(int seconds) {
    delay = seconds * 1000;
  }
  public void setStocks(int[] indices) {
    stockIndices = indices;
    updateStocks();
    fireTableDataChanged();
  }
  public void updateStocks() {
    stocks = new Stock[stockIndices.length];
    for (int i = 0; i < stocks.length; i++) {
      stocks[i] = market.getQuote(stockIndices[i]);
    }
  }
  public void run() {
    while (true) {
      // Blind update . . . we could check for real deltas if necessary
      updateStocks();
      // We know there are no new columns, so don"t fire a data change,
      // only
      // fire a row update . . . this keeps the table from flashing
      fireTableRowsUpdated(0, stocks.length - 1);
      try {
        Thread.sleep(delay);
      } catch (InterruptedException ie) {
      }
    }
  }
}
//Stock.java
//A simple aggregate class for storing stock market information on a single
//stock (symbol, price, etc.).
//
class Stock {
  String symbol;
  double price;
  double delta;
  Date lastUpdate;
  public Stock(String s, double p) {
    symbol = s;
    price = p;
    lastUpdate = new Date();
  }
  public void update(double d) {
    delta = d;
    price += delta;
  }
  public void print() {
    System.out.println(symbol + ": " + price + " (" + delta
        + ") last updated " + lastUpdate);
  }
}
//MYOSM.java
//Make Your Own Stock Market: A simple stock market simulator that contains a
//few stocks and their current prices (and deltas). It randomly adjusts the
//prices on stocks to give a dynamic feel to the data.
//
class MYOSM extends JFrame implements Runnable {
  Stock[] market = { new Stock("JTree", 14.57), new Stock("JTable", 17.44),
      new Stock("JList", 16.44), new Stock("JButton", 7.21),
      new Stock("JComponent", 27.40) };
  boolean monitor;
  Random rg = new Random();
  Thread runner;
  public MYOSM() {
    // Not meant to be shown as a real frame
    super("Thread only version . . .");
    runner = new Thread(this);
    runner.start();
  }
  // This version creates a real frame so that you can see how the typical
  // stocks get updated. It"s not meant to be used with other programs,
  // but rather as a debugging tool to make sure the market runs ok.
  public MYOSM(boolean monitorOn) {
    super("Stock Market Monitor");
    setSize(400, 100);
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    monitor = monitorOn;
    getContentPane().add(
        new JLabel("Trading is active.  "
            + "Close this window to close the market."),
        BorderLayout.CENTER);
    runner = new Thread(this);
    runner.start();
  }
  // Here"s the heart of our stock market. In an infinite loop, just pick a
  // random stock and update its price. To make the program interesting, we"ll
  // update a price every second.
  public void run() {
    while (true) {
      int whichStock = Math.abs(rg.nextInt()) % market.length;
      double delta = rg.nextDouble() - 0.4;
      market[whichStock].update(delta);
      if (monitor) {
        market[whichStock].print();
      }
      try {
        Thread.sleep(1000);
      } catch (InterruptedException ie) {
      }
    }
  }
  public Stock getQuote(int index) {
    return market[index];
  }
  // This method returns the list of all the symbols in the market table
  public String[] getSymbols() {
    String[] symbols = new String[market.length];
    for (int i = 0; i < market.length; i++) {
      symbols[i] = market[i].symbol;
    }
    return symbols;
  }
  public static void main(String args[]) {
    MYOSM myMarket = new MYOSM(args.length > 0);
    myMarket.setVisible(true);
  }
}





Custom table model, File data based Model

    
/*
Java Swing, 2nd Edition
By Marc Loy, Robert Eckstein, Dave Wood, James Elliott, Brian Cole
ISBN: 0-596-00408-7
Publisher: O"Reilly 
*/
// FileTable2.java
//A test frame for the custom table model, FileModel. This version uses a
//custom renderer (BigRenderer.java) to flag large files with an exclamation
//point icon.
import java.awt.BorderLayout;
import java.awt.ruponent;
import java.io.File;
import java.util.Date;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingConstants;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
public class FileTable2 extends JFrame {
  public FileTable2() {
    super("Custom TableModel Test");
    setSize(300, 200);
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    FileModel fm = new FileModel();
    JTable jt = new JTable(fm);
    jt.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
    jt.setColumnSelectionAllowed(true);
    jt.setDefaultRenderer(Number.class, new BigRenderer(1000));
    JScrollPane jsp = new JScrollPane(jt);
    getContentPane().add(jsp, BorderLayout.CENTER);
  }
  public static void main(String args[]) {
    FileTable2 ft = new FileTable2();
    ft.setVisible(true);
  }
}
//FileModel.java
//A custom table model to display information on a directory of files.
//
class FileModel extends AbstractTableModel {
  String titles[] = new String[] { "Directory?", "File Name", "Read?",
      "Write?", "Size", "Last Modified" };
  Class types[] = new Class[] { Boolean.class, String.class, Boolean.class,
      Boolean.class, Number.class, Date.class };
  Object data[][];
  public FileModel() {
    this(".");
  }
  public FileModel(String dir) {
    File pwd = new File(dir);
    setFileStats(pwd);
  }
  // Implement the methods of the TableModel interface we"re interested
  // in. Only getRowCount(), getColumnCount() and getValueAt() are
  // required. The other methods tailor the look of the table.
  public int getRowCount() {
    return data.length;
  }
  public int getColumnCount() {
    return titles.length;
  }
  public String getColumnName(int c) {
    return titles[c];
  }
  public Class getColumnClass(int c) {
    return types[c];
  }
  public Object getValueAt(int r, int c) {
    return data[r][c];
  }
  //  Our own method for setting/changing the current directory
  // being displayed. This method fills the data set with file info
  // from the given directory. It also fires an update event so this
  // method could also be called after the table is on display.
  public void setFileStats(File dir) {
    String files[] = dir.list();
    data = new Object[files.length][titles.length];
    for (int i = 0; i < files.length; i++) {
      File tmp = new File(files[i]);
      data[i][0] = new Boolean(tmp.isDirectory());
      data[i][1] = tmp.getName();
      data[i][2] = new Boolean(tmp.canRead());
      data[i][3] = new Boolean(tmp.canWrite());
      data[i][4] = new Long(tmp.length());
      data[i][5] = new Date(tmp.lastModified());
    }
    // Just in case anyone"s listening...
    fireTableDataChanged();
  }
}
//BigRenderer.java
//A renderer for numbers that shows an icon in front of big numbers.
//
class BigRenderer extends DefaultTableCellRenderer {
  double threshold;
  Icon bang = new ImageIcon("bang.gif");
  public BigRenderer(double t) {
    threshold = t;
    setHorizontalAlignment(JLabel.RIGHT);
    setHorizontalTextPosition(SwingConstants.RIGHT);
  }
  public Component getTableCellRendererComponent(JTable table, Object value,
      boolean isSelected, boolean hasFocus, int row, int col) {
    // be a little paranoid about where the user tries to use this renderer
    if (value instanceof Number) {
      if (((Number) value).doubleValue() > threshold) {
        setIcon(bang);
      } else {
        setIcon(null);
      }
    } else {
      setIcon(null);
    }
    return super.getTableCellRendererComponent(table, value, isSelected,
        hasFocus, row, col);
  }
}





Disable autoCreateColumnsFromModel

   
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
public class Main {
  public static void main(String[] argv) throws Exception {
    DefaultTableModel model = new DefaultTableModel();
    JTable table = new JTable(model);
    // Disable autoCreateColumnsFromModel
    table.setAutoCreateColumnsFromModel(false);
  }
}





extends AbstractTableModel to create custom model

    
/*
Definitive Guide to Swing for Java 2, Second Edition
By John Zukowski     
ISBN: 1-893115-78-X
Publisher: APress
*/
import java.util.Date;
import javax.swing.*;
import javax.swing.table.*;
import java.awt.*;
public class ColumnSample {
  public static void main(String args[]) {
    TableModel model = new AbstractTableModel() {
      Icon icon1 = new ImageIcon("TreeCollapsed.gif");
      Icon icon2 = new ImageIcon("TreeExpanded.gif");
      Object rowData[][] = {
          { "1", "ichi", Boolean.TRUE, new Date("01/01/2000"), icon1 },
          { "2", "ni", Boolean.TRUE, new Date("04/15/1999"), icon2 },
          { "3", "san", Boolean.FALSE, new Date("12/07/1941"), icon2 },
          { "4", "shi", Boolean.TRUE, new Date("02/29/2000"), icon1 },
          { "5", "go", Boolean.FALSE, new Date("05/23/1995"), icon1 }, };
      String columnNames[] = { "English", "Japanese", "Boolean", "Date",
          "ImageIcon" };
      public int getColumnCount() {
        return columnNames.length;
      }
      public String getColumnName(int column) {
        return columnNames[column];
      }
      public int getRowCount() {
        return rowData.length;
      }
      public Object getValueAt(int row, int column) {
        return rowData[row][column];
      }
      public Class getColumnClass(int column) {
        return (getValueAt(0, column).getClass());
      }
    };
    JFrame frame = new JFrame("Column Renderer Table");
    JTable table = new JTable(model);
    JScrollPane scrollPane = new JScrollPane(table);
    frame.getContentPane().add(scrollPane, BorderLayout.CENTER);
    frame.setSize(400, 150);
    frame.setVisible(true);
  }
}





extends DefaultTableModel to create your own table model and build table from that

    
import java.awt.BorderLayout;
import java.util.Vector;
import javax.swing.DefaultCellEditor;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;
public class TableSample2 {
  public static void main(String args[]) {
    Object rows[][] = { { "one", "ichi - \u4E00", "un" },
        { "two", "ni - \u4E8C", "deux" },
        { "three", "san - \u4E09", "trois" },
        { "four", "shi - \u56DB", "quatre" },
        { "five", "go - \u4E94", "cinq" },
        { "six", "roku - \u516D", "treiza" },
        { "seven", "shichi - \u4E03", "sept" },
        { "eight", "hachi - \u516B", "huit" },
        { "nine", "kyu - \u4E5D", "neuf" },
        { "ten", "ju - \u5341", "dix" }
    };
    Object options[] = { "un", "deux", "trois", "quatre", "cinq", "treiza",
        "sept", "huit", "neuf", "dix" };
    JComboBox comboBox = new JComboBox(options);
    comboBox.setMaximumRowCount(4);
    TableCellEditor editor = new DefaultCellEditor(comboBox);
    Object headers[] = { "English", "Japanese", "French" };
    JFrame frame = new JFrame("JTable Anatomy");
    class CustomTableModel extends DefaultTableModel {
      public CustomTableModel(Object rowData[][], Object columnNames[]) {
        super(rowData, columnNames);
      }
      public Class getColumnClass(int col) {
        Vector v = (Vector) dataVector.elementAt(0);
        return v.elementAt(col).getClass();
      }
      public boolean isCellEditable(int row, int col) {
        return true;
      }
    }
    JTable table = new JTable(new DefaultTableModel(rows, headers));
    //    ColumnModelUtilities.removeHeaders(table.getColumnModel());
    table.getColumnModel().getColumn(2).setCellEditor(editor);
    JScrollPane scrollPane = new JScrollPane(table);
    frame.getContentPane().add(scrollPane, BorderLayout.CENTER);
    frame.setSize(300, 150);
    frame.setVisible(true);
  }
}





File data Table: file name, size, type

    
/*
 * This example is from the book "Java Foundation Classes in a Nutshell".
 * Written by David Flanagan. Copyright (c) 1999 by O"Reilly & Associates.  
 * You may distribute this source code for non-commercial purposes only.
 * You may study, modify, and use this example for any purpose, as long as
 * this notice is retained.  Note that this example is provided "as is",
 * WITHOUT WARRANTY of any kind either expressed or implied.
 */
import javax.swing.*;
import javax.swing.table.*;
import java.io.File;
import java.util.Date;
public class FileTableDemo {
  public static void main(String[] args) {
    // Figure out what directory to display;
    File dir;
    if (args.length > 0) dir = new File(args[0]);
    else dir = new File(System.getProperty("user.home"));
    // Create a TableModel object to represent the contents of the directory
    FileTableModel model = new FileTableModel(dir);
    // Create a JTable and tell it to display our model
    JTable table = new JTable(model);
    // Display it all in a scrolling window and make the window appear
    JFrame frame = new JFrame("FileTableDemo");
    frame.getContentPane().add(new JScrollPane(table), "Center");
    frame.setSize(600, 400);
    frame.setVisible(true);
  }
}
/**
 * The methods in this class allow the JTable component to get
 * and display data about the files in a specified directly.
 * It represents a table with 6 columns: file name, size, modification date, 
 * plus three columns for flags: directory, readable, writable
 **/
class FileTableModel extends AbstractTableModel {
  protected File dir;
  protected String[] filenames;
  protected String[] columnNames = new String[] {
    "name", "size", "last modified", "directory?", "readable?", "writable?"
  };
  protected Class[] columnClasses = new Class[] { 
    String.class, Long.class, Date.class, 
      Boolean.class, Boolean.class, Boolean.class
  };
  // This table model works for any one given directory
  public FileTableModel(File dir) { 
    this.dir = dir; 
    this.filenames = dir.list();  // Store a list of files in the directory
  }
  // These are easy methods.
  public int getColumnCount() { return 6; }  // A constant for this model
  public int getRowCount() { return filenames.length; }  // # of files in dir
  // Information about each column.
  public String getColumnName(int col) { return columnNames[col]; }
  public Class getColumnClass(int col) { return columnClasses[col]; }
  // The method that must actually return the value of each cell.
  public Object getValueAt(int row, int col) {
    File f = new File(dir, filenames[row]);
    switch(col) {
    case 0: return filenames[row];
    case 1: return new Long(f.length());
    case 2: return new Date(f.lastModified());
    case 3: return f.isDirectory() ? Boolean.TRUE : Boolean.FALSE;
    case 4: return f.canRead() ? Boolean.TRUE : Boolean.FALSE;
    case 5: return f.canWrite() ? Boolean.TRUE : Boolean.FALSE;
    default: return null;
    }
  }
}





Fixed data vs dynamic data Table

    
import java.awt.BorderLayout;
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JViewport;
import javax.swing.ListSelectionModel;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableModel;
public class FixedTable {
  public static void main(String args[]) {
    final Object rowData[][] = {
        { "1", "one", "ichi", "un", "I", "\u4E00" },
        { "2", "two", "ni", "deux", "II", "\u4E8C" },
        { "3", "three", "san", "trois", "III", "\u4E09" },
        { "4", "four", "shi", "quatre", "IV", "\u56DB" },
        { "5", "five", "go", "cinq", "V", "\u4E94" },
        { "6", "six", "roku", "treiza", "VI", "\u516D" },
        { "7", "seven", "shichi", "sept", "VII", "\u4E03" },
        { "8", "eight", "hachi", "huit", "VIII", "\u516B" },
        { "9", "nine", "kyu", "neur", "IX", "\u4E5D" },
        { "10", "ten", "ju", "dix", "X", "\u5341" } };
    final String columnNames[] = { "#", "English", "Japanese", "French",
        "Roman", "Kanji" };
    TableModel fixedColumnModel = new AbstractTableModel() {
      public int getColumnCount() {
        return 1;
      }
      public String getColumnName(int column) {
        return columnNames[column];
      }
      public int getRowCount() {
        return rowData.length;
      }
      public Object getValueAt(int row, int column) {
        return rowData[row][column];
      }
    };
    TableModel mainModel = new AbstractTableModel() {
      public int getColumnCount() {
        return columnNames.length - 1;
      }
      public String getColumnName(int column) {
        return columnNames[column + 1];
      }
      public int getRowCount() {
        return rowData.length;
      }
      public Object getValueAt(int row, int column) {
        return rowData[row][column + 1];
      }
    };
    JTable fixedTable = new JTable(fixedColumnModel);
    fixedTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
    //    fixedTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    JTable mainTable = new JTable(mainModel);
    mainTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
    //    mainTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    ListSelectionModel model = fixedTable.getSelectionModel();
    mainTable.setSelectionModel(model);
    JScrollPane scrollPane = new JScrollPane(mainTable);
    Dimension fixedSize = fixedTable.getPreferredSize();
    JViewport viewport = new JViewport();
    viewport.setView(fixedTable);
    viewport.setPreferredSize(fixedSize);
    viewport.setMaximumSize(fixedSize);
    scrollPane.setCorner(JScrollPane.UPPER_LEFT_CORNER, fixedTable
        .getTableHeader());
    scrollPane.setRowHeaderView(viewport);
    JFrame frame = new JFrame("Fixed Column Table");
    frame.getContentPane().add(scrollPane, BorderLayout.CENTER);
    frame.setSize(300, 150);
    frame.setVisible(true);
  }
}





Get all the table data from DefaultTableModel

   
import java.util.ArrayList;
import java.util.Vector;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
public class Main {
  public static void main(String[] argv) throws Exception {
    DefaultTableModel model = new DefaultTableModel();
    JTable table = new JTable(model);
    model.addColumn("Col1");
    model.addRow(new Object[] { "r1" });
    model.addRow(new Object[] { "r2" });
    model.addRow(new Object[] { "r3" });
    
    // Get all the table data
    Vector data = model.getDataVector();
    JFrame f = new JFrame();
    f.setSize(300, 300);
    f.add(new JScrollPane(table));
    f.setVisible(true);
  }
}





Hard code data in array for TableModel

    
import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableModel;
public class AbstractSample {
  public static void main(String args[]) {
    TableModel model = new AbstractTableModel() {
      Object rowData[][] = { { "one", "ichi" }, { "two", "ni" },
          { "three", "san" }, { "four", "shi" }, { "five", "go" },
          { "six", "roku" }, { "seven", "shichi" },
          { "eight", "hachi" }, { "nine", "kyu" }, { "ten", "ju" } };
      Object columnNames[] = { "English", "Japanese" };
      public String getColumnName(int column) {
        return columnNames[column].toString();
      }
      public int getRowCount() {
        return rowData.length;
      }
      public int getColumnCount() {
        return columnNames.length;
      }
      public Object getValueAt(int row, int col) {
        return rowData[row][col];
      }
    };
    JFrame frame = new JFrame("Abstract Sample");
    JTable table = new JTable(model);
    JScrollPane scrollPane = new JScrollPane(table);
    frame.getContentPane().add(scrollPane, BorderLayout.CENTER);
    frame.setSize(300, 150);
    frame.setVisible(true);
  }
}





Insert a new column to a table

   
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
public class Main {
  public static void main(String[] argv) throws Exception {
    DefaultTableModel model = new DefaultTableModel();
    JTable table = new JTable(model);
    model.addColumn("Col1");
    model.addRow(new Object[] { "r1" });
    model.addRow(new Object[] { "r2" });
    model.addRow(new Object[] { "r3" });
    
    Vector data = model.getDataVector();
    Vector row = (Vector) data.elementAt(1);
    int mColIndex = 0;
    List colData = new ArrayList(table.getRowCount());
    for (int i = 0; i < table.getRowCount(); i++) {
      row = (Vector) data.elementAt(i);
      colData.add(row.get(mColIndex));
    }
    // Append a new column with copied data
    model.addColumn("Col3", colData.toArray());
    
    JFrame f = new JFrame();
    f.setSize(300, 300);
    f.add(new JScrollPane(table));
    f.setVisible(true);
  }
}





JTable class using default table models and a convenience

    
/*
Java Swing, 2nd Edition
By Marc Loy, Robert Eckstein, Dave Wood, James Elliott, Brian Cole
ISBN: 0-596-00408-7
Publisher: O"Reilly 
*/
// SimpleTable.java
//A test of the JTable class using default table models and a convenience
//constructor.
//
import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
public class SimpleTable extends JFrame {
  public SimpleTable() {
    super("Simple JTable Test");
    setSize(300, 200);
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    JTable jt = new JTable(new String[][] { { "This", "is" },
        { "a", "Test" } }, new String[] { "Column", "Header" });
    JScrollPane jsp = new JScrollPane(jt);
    getContentPane().add(jsp, BorderLayout.CENTER);
  }
  public static void main(String args[]) {
    SimpleTable st = new SimpleTable();
    st.setVisible(true);
  }
}





Map TableModel

    
/*
 * Project: Gulden Utilies
 * Class:   de.gulden.util.swing.MapTableModel
 * Version: snapshot-beautyj-1.1
 *
 * Date:    2004-09-29
 *
 * This is a snapshot version of the Gulden Utilities,
 * it is not released as a seperate version.
 *  
 * Note:    Contains auto-generated Javadoc comments created by BeautyJ.
 *  
 * This is licensed under the GNU Lesser General Public License (LGPL)
 * and comes with NO WARRANTY.
 *
 * Author:  Jens Gulden
 * Email:   amoda@jensgulden.de
 */

import java.util.*;
import java.util.Map;
import javax.swing.table.AbstractTableModel;
/**
 * Class MapTableModel.
 *  
 * @author  Jens Gulden
 * @version  snapshot-beautyj-1.1
 */
public class MapTableModel extends AbstractTableModel {
    // ------------------------------------------------------------------------
    // --- fields                                                           ---
    // ------------------------------------------------------------------------
    /**
     * The map.
     */
    protected Map map;
    /**
     * The column names array.
     */
    protected String[] columnNames;

    // ------------------------------------------------------------------------
    // --- constructors                                                     ---
    // ------------------------------------------------------------------------
    /**
     * Creates a new instance of MapTableModel.
     */
    public MapTableModel() {
        super();
    }
    /**
     * Creates a new instance of MapTableModel.
     */
    public MapTableModel(Map map) {
        this(map,"Entry","Value");
    }
    /**
     * Creates a new instance of MapTableModel.
     */
    public MapTableModel(Map map, String keyName, String valueName) {
        this();
        setMap(map);
        setColumnNames(keyName,valueName);
    }

    // ------------------------------------------------------------------------
    // --- methods                                                          ---
    // ------------------------------------------------------------------------
    /**
     * Returns the row count.
     */
    public int getRowCount() {
        return map.size();
    }
    /**
     * Returns the column count.
     */
    public int getColumnCount() {
        return 2;
    }
    /**
     * Returns the value at.
     */
    public Object getValueAt(int row, int column) {
        Object[] entries=map.entrySet().toArray();
        Map.Entry entry=(Map.Entry)entries[row];
        if (column==0) {
            return entry.getKey();
        } else if (column==1) { // column==1
            return entry.getValue();
        } else {
            throw new IndexOutOfBoundsException("MapTableModel provides a 2-column table, column-index "+column+" is illegal.");
        }
    }
    /**
     * Returns the column name.
     */
    public String getColumnName(int column) {
        return columnNames[column];
    }
    /**
     * Sets the column names.
     */
    public void setColumnNames(String keyName, String valueName) {
        String[] names={keyName,valueName};
        columnNames=names;
    }
    /**
     * Returns the map.
     */
    public Map getMap() {
        return map;
    }
    /**
     * Sets the map.
     */
    public void setMap(Map _map) {
        map = _map;
    }
} // end MapTableModel





Move the first row to the end of the table

   
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
public class Main {
  public static void main(String[] argv) throws Exception {
    DefaultTableModel model = new DefaultTableModel();
    JTable table = new JTable(model);
    model.addColumn("Col1");
    model.addRow(new Object[] { "r1" });
    model.addRow(new Object[] { "r2" });
    model.addRow(new Object[] { "r3" });
    // Move the first row to the end of the table
    model.moveRow(0, 0, model.getRowCount() - 1);
    JFrame f = new JFrame();
    f.setSize(300, 300);
    f.add(new JScrollPane(table));
    f.setVisible(true);
  }
}





Move the first two rows to the end of the table

   
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
public class Main {
  public static void main(String[] argv) throws Exception {
    DefaultTableModel model = new DefaultTableModel();
    JTable table = new JTable(model);
    model.addColumn("Col1");
    model.addRow(new Object[] { "r1" });
    model.addRow(new Object[] { "r2" });
    model.addRow(new Object[] { "r3" });
    // Move the first two rows to the end of the table
    model.moveRow(0, 1, model.getRowCount() - 2);
    
    JFrame f = new JFrame();
    f.setSize(300, 300);
    f.add(new JScrollPane(table));
    f.setVisible(true);
  }
}





Move the last row to the beginning of the table

   
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
public class Main {
  public static void main(String[] argv) throws Exception {
    DefaultTableModel model = new DefaultTableModel();
    JTable table = new JTable(model);
    model.addColumn("Col1");
    model.addRow(new Object[] { "r1" });
    model.addRow(new Object[] { "r2" });
    model.addRow(new Object[] { "r3" });
    // Move the last row to the beginning of the table
    model.moveRow(model.getRowCount() - 1, model.getRowCount() - 1, 0);
    JFrame f = new JFrame();
    f.setSize(300, 300);
    f.add(new JScrollPane(table));
    f.setVisible(true);
  }
}





Move the last two rows to the start of the table

   
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
public class Main {
  public static void main(String[] argv) throws Exception {
    DefaultTableModel model = new DefaultTableModel();
    JTable table = new JTable(model);
    model.addColumn("Col1");
    model.addRow(new Object[] { "r1" });
    model.addRow(new Object[] { "r2" });
    model.addRow(new Object[] { "r3" });
    // Move the last two rows to the start of the table
    model.moveRow(model.getRowCount() - 2, model.getRowCount() - 1, 0);
    
    JFrame f = new JFrame();
    f.setSize(300, 300);
    f.add(new JScrollPane(table));
    f.setVisible(true);
  }
}





Overwrite the date from the first row with DefaultTableModel

   
import java.util.ArrayList;
import java.util.Vector;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
public class Main {
  public static void main(String[] argv) throws Exception {
    DefaultTableModel model = new DefaultTableModel();
    JTable table = new JTable(model);
    model.addColumn("Col1");
    model.addRow(new Object[] { "r1" });
    model.addRow(new Object[] { "r2" });
    model.addRow(new Object[] { "r3" });
    
    Vector data = model.getDataVector();
    Vector row = (Vector) data.elementAt(1);
    // Overwrite the first row with the copy
    Vector firstRow = (Vector) data.elementAt(0);
    for (int i = 0; i < row.size(); i++) {
      firstRow.set(i, row.get(i));
    }
    
    JFrame f = new JFrame();
    f.setSize(300, 300);
    f.add(new JScrollPane(table));
    f.setVisible(true);
  }
}





Paging JTable(Table) Model with an input field for dynamically altering the size of a page.

    
/*
Java Swing, 2nd Edition
By Marc Loy, Robert Eckstein, Dave Wood, James Elliott, Brian Cole
ISBN: 0-596-00408-7
Publisher: O"Reilly 
*/
// PagingTester2.java
//A quick application that demonstrates the PagingModel. This version has
//an input field for dynamically altering the size of a page.
//
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.ruponent;
import java.awt.Graphics;
import java.awt.Polygon;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.ScrollPaneConstants;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableModel;
public class PagingTester2 extends JFrame {
  public PagingTester2() {
    super("Paged JTable Test");
    setSize(300, 200);
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    final PagingModel pm = new PagingModel();
    final JTable jt = new JTable(pm);
    // Use our own custom scrollpane.
    JScrollPane jsp = PagingModel.createPagingScrollPaneForTable(jt);
    getContentPane().add(jsp, BorderLayout.CENTER);
    // Property features testing
    JPanel p = new JPanel();
    p.add(new JLabel("Page Size: "));
    final JTextField tf = new JTextField("100", 6);
    p.add(tf);
    tf.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent ae) {
        pm.setPageSize(Integer.parseInt(tf.getText()));
      }
    });
    getContentPane().add(p, BorderLayout.SOUTH);
  }
  public static void main(String args[]) {
    PagingTester2 pt = new PagingTester2();
    pt.setVisible(true);
  }
}
//PagingModel.java
//A larger table model that performs "paging" of its data. This model
//reports a small number of rows (like 100 or so) as a "page" of data. You
//can switch pages to view all of the rows as needed using the pageDown()
//and pageUp() methods. Presumably, access to the other pages of data is
//dictated by other GUI elements such as up/down buttons, or maybe a text
//field that allows you to enter the page number you want to display.
//
class PagingModel extends AbstractTableModel {
  protected int pageSize;
  protected int pageOffset;
  protected Record[] data;
  public PagingModel() {
    this(10000, 100);
  }
  public PagingModel(int numRows, int size) {
    data = new Record[numRows];
    pageSize = size;
    // Fill our table with random data (from the Record() constructor).
    for (int i = 0; i < data.length; i++) {
      data[i] = new Record();
    }
  }
  // Return values appropriate for the visible table part.
  public int getRowCount() {
    return Math.min(pageSize, data.length);
  }
  public int getColumnCount() {
    return Record.getColumnCount();
  }
  // Work only on the visible part of the table.
  public Object getValueAt(int row, int col) {
    int realRow = row + (pageOffset * pageSize);
    return data[realRow].getValueAt(col);
  }
  public String getColumnName(int col) {
    return Record.getColumnName(col);
  }
  // Use this method to figure out which page you are on.
  public int getPageOffset() {
    return pageOffset;
  }
  public int getPageCount() {
    return (int) Math.ceil((double) data.length / pageSize);
  }
  // Use this method if you want to know how big the real table is . . . we
  // could also write "getRealValueAt()" if needed.
  public int getRealRowCount() {
    return data.length;
  }
  public int getPageSize() {
    return pageSize;
  }
  public void setPageSize(int s) {
    if (s == pageSize) {
      return;
    }
    int oldPageSize = pageSize;
    pageSize = s;
    pageOffset = (oldPageSize * pageOffset) / pageSize;
    fireTableDataChanged();
    /*
     * if (pageSize < oldPageSize) { fireTableRowsDeleted(pageSize,
     * oldPageSize - 1); } else { fireTableRowsInserted(oldPageSize,
     * pageSize - 1); }
     */
  }
  // Update the page offset and fire a data changed (all rows).
  public void pageDown() {
    if (pageOffset < getPageCount() - 1) {
      pageOffset++;
      fireTableDataChanged();
    }
  }
  // Update the page offset and fire a data changed (all rows).
  public void pageUp() {
    if (pageOffset > 0) {
      pageOffset--;
      fireTableDataChanged();
    }
  }
  // We provide our own version of a scrollpane that includes
  // the page up and page down buttons by default.
  public static JScrollPane createPagingScrollPaneForTable(JTable jt) {
    JScrollPane jsp = new JScrollPane(jt);
    TableModel tmodel = jt.getModel();
    // Don"t choke if this is called on a regular table . . .
    if (!(tmodel instanceof PagingModel)) {
      return jsp;
    }
    // Okay, go ahead and build the real scrollpane
    final PagingModel model = (PagingModel) tmodel;
    final JButton upButton = new JButton(new ArrowIcon(ArrowIcon.UP));
    upButton.setEnabled(false); // starts off at 0, so can"t go up
    final JButton downButton = new JButton(new ArrowIcon(ArrowIcon.DOWN));
    if (model.getPageCount() <= 1) {
      downButton.setEnabled(false); // One page...can"t scroll down
    }
    upButton.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent ae) {
        model.pageUp();
        // If we hit the top of the data, disable the up button.
        if (model.getPageOffset() == 0) {
          upButton.setEnabled(false);
        }
        downButton.setEnabled(true);
      }
    });
    downButton.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent ae) {
        model.pageDown();
        // If we hit the bottom of the data, disable the down button.
        if (model.getPageOffset() == (model.getPageCount() - 1)) {
          downButton.setEnabled(false);
        }
        upButton.setEnabled(true);
      }
    });
    // Turn on the scrollbars; otherwise we won"t get our corners.
    jsp
        .setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
    jsp
        .setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
    // Add in the corners (page up/down).
    jsp.setCorner(ScrollPaneConstants.UPPER_RIGHT_CORNER, upButton);
    jsp.setCorner(ScrollPaneConstants.LOWER_RIGHT_CORNER, downButton);
    return jsp;
  }
}
//Record.java
//A simple data structure for use with the PagingModel demo.
//
class Record {
  static String[] headers = { "Record Number", "Batch Number", "Reserved" };
  static int counter;
  String[] data;
  public Record() {
    data = new String[] { "" + (counter++),
        "" + System.currentTimeMillis(), "Reserved" };
  }
  public String getValueAt(int i) {
    return data[i];
  }
  public static String getColumnName(int i) {
    return headers[i];
  }
  public static int getColumnCount() {
    return headers.length;
  }
}
//ArrowIcon.java
//A simple implementation of the Icon interface that can make
//Up and Down arrows.
//
class ArrowIcon implements Icon {
  public static final int UP = 0;
  public static final int DOWN = 1;
  private int direction;
  private Polygon pagePolygon = new Polygon(new int[] { 2, 4, 4, 10, 10, 2 },
      new int[] { 4, 4, 2, 2, 12, 12 }, 6);
  private int[] arrowX = { 4, 9, 6 };
  private Polygon arrowUpPolygon = new Polygon(arrowX,
      new int[] { 10, 10, 4 }, 3);
  private Polygon arrowDownPolygon = new Polygon(arrowX,
      new int[] { 6, 6, 11 }, 3);
  public ArrowIcon(int which) {
    direction = which;
  }
  public int getIconWidth() {
    return 14;
  }
  public int getIconHeight() {
    return 14;
  }
  public void paintIcon(Component c, Graphics g, int x, int y) {
    g.setColor(Color.black);
    pagePolygon.translate(x, y);
    g.drawPolygon(pagePolygon);
    pagePolygon.translate(-x, -y);
    if (direction == UP) {
      arrowUpPolygon.translate(x, y);
      g.fillPolygon(arrowUpPolygon);
      arrowUpPolygon.translate(-x, -y);
    } else {
      arrowDownPolygon.translate(x, y);
      g.fillPolygon(arrowDownPolygon);
      arrowDownPolygon.translate(-x, -y);
    }
  }
}





Paging or pagable JTable(Table) Model for large data set

    
/*
Java Swing, 2nd Edition
By Marc Loy, Robert Eckstein, Dave Wood, James Elliott, Brian Cole
ISBN: 0-596-00408-7
Publisher: O"Reilly 
*/
// PagingTester.java
//A quick application that demonstrates the PagingModel.
//
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.ruponent;
import java.awt.Graphics;
import java.awt.Polygon;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ScrollPaneConstants;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableModel;
public class PagingTester extends JFrame {
  public PagingTester() {
    super("Paged JTable Test");
    setSize(300, 200);
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    PagingModel pm = new PagingModel();
    JTable jt = new JTable(pm);
    // Use our own custom scrollpane.
    JScrollPane jsp = PagingModel.createPagingScrollPaneForTable(jt);
    getContentPane().add(jsp, BorderLayout.CENTER);
  }
  public static void main(String args[]) {
    PagingTester pt = new PagingTester();
    pt.setVisible(true);
  }
}
//PagingModel.java
//A larger table model that performs "paging" of its data. This model
//reports a small number of rows (like 100 or so) as a "page" of data. You
//can switch pages to view all of the rows as needed using the pageDown()
//and pageUp() methods. Presumably, access to the other pages of data is
//dictated by other GUI elements such as up/down buttons, or maybe a text
//field that allows you to enter the page number you want to display.
//
class PagingModel extends AbstractTableModel {
  protected int pageSize;
  protected int pageOffset;
  protected Record[] data;
  public PagingModel() {
    this(10000, 100);
  }
  public PagingModel(int numRows, int size) {
    data = new Record[numRows];
    pageSize = size;
    // Fill our table with random data (from the Record() constructor).
    for (int i = 0; i < data.length; i++) {
      data[i] = new Record();
    }
  }
  // Return values appropriate for the visible table part.
  public int getRowCount() {
    return Math.min(pageSize, data.length);
  }
  public int getColumnCount() {
    return Record.getColumnCount();
  }
  // Work only on the visible part of the table.
  public Object getValueAt(int row, int col) {
    int realRow = row + (pageOffset * pageSize);
    return data[realRow].getValueAt(col);
  }
  public String getColumnName(int col) {
    return Record.getColumnName(col);
  }
  // Use this method to figure out which page you are on.
  public int getPageOffset() {
    return pageOffset;
  }
  public int getPageCount() {
    return (int) Math.ceil((double) data.length / pageSize);
  }
  // Use this method if you want to know how big the real table is . . . we
  // could also write "getRealValueAt()" if needed.
  public int getRealRowCount() {
    return data.length;
  }
  public int getPageSize() {
    return pageSize;
  }
  public void setPageSize(int s) {
    if (s == pageSize) {
      return;
    }
    int oldPageSize = pageSize;
    pageSize = s;
    pageOffset = (oldPageSize * pageOffset) / pageSize;
    fireTableDataChanged();
    /*
     * if (pageSize < oldPageSize) { fireTableRowsDeleted(pageSize,
     * oldPageSize - 1); } else { fireTableRowsInserted(oldPageSize,
     * pageSize - 1); }
     */
  }
  // Update the page offset and fire a data changed (all rows).
  public void pageDown() {
    if (pageOffset < getPageCount() - 1) {
      pageOffset++;
      fireTableDataChanged();
    }
  }
  // Update the page offset and fire a data changed (all rows).
  public void pageUp() {
    if (pageOffset > 0) {
      pageOffset--;
      fireTableDataChanged();
    }
  }
  // We provide our own version of a scrollpane that includes
  // the page up and page down buttons by default.
  public static JScrollPane createPagingScrollPaneForTable(JTable jt) {
    JScrollPane jsp = new JScrollPane(jt);
    TableModel tmodel = jt.getModel();
    // Don"t choke if this is called on a regular table . . .
    if (!(tmodel instanceof PagingModel)) {
      return jsp;
    }
    // Okay, go ahead and build the real scrollpane
    final PagingModel model = (PagingModel) tmodel;
    final JButton upButton = new JButton(new ArrowIcon(ArrowIcon.UP));
    upButton.setEnabled(false); // starts off at 0, so can"t go up
    final JButton downButton = new JButton(new ArrowIcon(ArrowIcon.DOWN));
    if (model.getPageCount() <= 1) {
      downButton.setEnabled(false); // One page...can"t scroll down
    }
    upButton.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent ae) {
        model.pageUp();
        // If we hit the top of the data, disable the up button.
        if (model.getPageOffset() == 0) {
          upButton.setEnabled(false);
        }
        downButton.setEnabled(true);
      }
    });
    downButton.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent ae) {
        model.pageDown();
        // If we hit the bottom of the data, disable the down button.
        if (model.getPageOffset() == (model.getPageCount() - 1)) {
          downButton.setEnabled(false);
        }
        upButton.setEnabled(true);
      }
    });
    // Turn on the scrollbars; otherwise we won"t get our corners.
    jsp
        .setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
    jsp
        .setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
    // Add in the corners (page up/down).
    jsp.setCorner(ScrollPaneConstants.UPPER_RIGHT_CORNER, upButton);
    jsp.setCorner(ScrollPaneConstants.LOWER_RIGHT_CORNER, downButton);
    return jsp;
  }
}
//Record.java
//A simple data structure for use with the PagingModel demo.
//
class Record {
  static String[] headers = { "Record Number", "Batch Number", "Reserved" };
  static int counter;
  String[] data;
  public Record() {
    data = new String[] { "" + (counter++),
        "" + System.currentTimeMillis(), "Reserved" };
  }
  public String getValueAt(int i) {
    return data[i];
  }
  public static String getColumnName(int i) {
    return headers[i];
  }
  public static int getColumnCount() {
    return headers.length;
  }
}
//ArrowIcon.java
//A simple implementation of the Icon interface that can make
//Up and Down arrows.
//
class ArrowIcon implements Icon {
  public static final int UP = 0;
  public static final int DOWN = 1;
  private int direction;
  private Polygon pagePolygon = new Polygon(new int[] { 2, 4, 4, 10, 10, 2 },
      new int[] { 4, 4, 2, 2, 12, 12 }, 6);
  private int[] arrowX = { 4, 9, 6 };
  private Polygon arrowUpPolygon = new Polygon(arrowX,
      new int[] { 10, 10, 4 }, 3);
  private Polygon arrowDownPolygon = new Polygon(arrowX,
      new int[] { 6, 6, 11 }, 3);
  public ArrowIcon(int which) {
    direction = which;
  }
  public int getIconWidth() {
    return 14;
  }
  public int getIconHeight() {
    return 14;
  }
  public void paintIcon(Component c, Graphics g, int x, int y) {
    g.setColor(Color.black);
    pagePolygon.translate(x, y);
    g.drawPolygon(pagePolygon);
    pagePolygon.translate(-x, -y);
    if (direction == UP) {
      arrowUpPolygon.translate(x, y);
      g.fillPolygon(arrowUpPolygon);
      arrowUpPolygon.translate(-x, -y);
    } else {
      arrowDownPolygon.translate(x, y);
      g.fillPolygon(arrowDownPolygon);
      arrowDownPolygon.translate(-x, -y);
    }
  }
}





Remove the first row from a table with DefaultTableModel

   
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
public class Main {
  public static void main(String[] argv) throws Exception {
    DefaultTableModel model = new DefaultTableModel();
    JTable table = new JTable(model);
    model.addColumn("Col1");
    model.addRow(new Object[] { "r1" });
    model.addRow(new Object[] { "r2" });
    model.addRow(new Object[] { "r3" });
    // Remove the first row
    model.removeRow(0);
    JFrame f = new JFrame();
    f.setSize(300, 300);
    f.add(new JScrollPane(table));
    f.setVisible(true);
  }
}





Remove the first visible column without removing the underlying data

   

import java.util.Enumeration;
import java.util.Vector;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
public class Main {
  public static void main(String[] argv) throws Exception {
    DefaultTableModel model = new MyDefaultTableModel();
    JTable table = new JTable(model);
    table.setModel(model);
    model.addColumn("Col1");
    model.addColumn("Col2");
    model.addColumn("Col3");
    model.addRow(new Object[] { "v1" });

    table.removeColumn(table.getColumnModel().getColumn(0));
    }
}
class MyDefaultTableModel extends DefaultTableModel {
  public Vector getColumnIdentifiers() {
    return columnIdentifiers;
  }
}





Remove the last row from a table with DefaultTableModel

   
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
public class Main {
  public static void main(String[] argv) throws Exception {
    DefaultTableModel model = new DefaultTableModel();
    JTable table = new JTable(model);
    // Create some data
    model.addColumn("Col1");
    model.addRow(new Object[] { "r1" });
    model.addRow(new Object[] { "r2" });
    model.addRow(new Object[] { "r3" });
    model.removeRow(model.getRowCount() - 1);
    JFrame f = new JFrame();
    f.setSize(300, 300);
    f.add(new JScrollPane(table));
    f.setVisible(true);
  }
}





Returns the visible columns in the order that they appear in the model

   
import java.util.ArrayList;
import java.util.Collections;
import java.util.ruparator;
import java.util.Enumeration;
import java.util.List;
import javax.swing.JTable;
import javax.swing.table.TableColumn;
public class Main {
  public static void main(String[] argv) {
  }
  // 
  public TableColumn[] getColumnsInModel(JTable table) {
    List result = new ArrayList();
    for (Enumeration e = table.getColumnModel().getColumns(); e.hasMoreElements();) {
      result.add((TableColumn) e.nextElement());
    }
    Collections.sort(result, new TableColumnComparator());
    return (TableColumn[]) result.toArray(new TableColumn[result.size()]);
  }
}
class TableColumnComparator implements Comparator {
  public int compare(Object a, Object b) {
    TableColumn c1 = (TableColumn) a;
    TableColumn c2 = (TableColumn) b;
    if (c1.getModelIndex() < c2.getModelIndex()) {
      return -1;
    } else if (c1.getModelIndex() == c2.getModelIndex()) {
      return 0;
    } else {
      return 1;
    }
  }
}





Sharing a Table Model Between JTable Components

   
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
public class Main {
  public static void main(String[] argv) {
    DefaultTableModel model = new DefaultTableModel();
    JTable table1 = new JTable(model);
    JTable table2 = new JTable(model);
    JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
    splitPane.add(new JScrollPane(table1));
    splitPane.add(new JScrollPane(table2));
    table1.getColumnModel().removeColumn(table1.getColumnModel().getColumn(0));
  }
}





Stocks data Table: illustrate the TableModel

    
/*
Swing, Second Edition
by Matthew Robinson, Pavel Vorobiev
*/
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Vector;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingConstants;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableColumn;
public class StocksTable extends JFrame {
  protected JTable m_table;
  protected StockTableData m_data;
  protected JLabel m_title;
  public StocksTable() {
    super("Stocks Table");
    setSize(600, 300);
    m_data = new StockTableData();
    m_title = new JLabel(m_data.getTitle(), new ImageIcon("money.gif"),
        SwingConstants.LEFT);
    m_title.setFont(new Font("TimesRoman", Font.BOLD, 24));
    m_title.setForeground(Color.black);
    getContentPane().add(m_title, BorderLayout.NORTH);
    m_table = new JTable();
    m_table.setAutoCreateColumnsFromModel(false);
    m_table.setModel(m_data);
    for (int k = 0; k < StockTableData.m_columns.length; k++) {
      DefaultTableCellRenderer renderer = new DefaultTableCellRenderer();
      renderer
          .setHorizontalAlignment(StockTableData.m_columns[k].m_alignment);
      TableColumn column = new TableColumn(k,
          StockTableData.m_columns[k].m_width, renderer, null);
      m_table.addColumn(column);
    }
    JTableHeader header = m_table.getTableHeader();
    header.setUpdateTableInRealTime(false);
    JScrollPane ps = new JScrollPane();
    ps.getViewport().add(m_table);
    getContentPane().add(ps, BorderLayout.CENTER);
    WindowListener wndCloser = new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        System.exit(0);
      }
    };
    addWindowListener(wndCloser);
    setVisible(true);
  }
  public static void main(String argv[]) {
    new StocksTable();
  }
}
class StockData {
  public String m_symbol;
  public String m_name;
  public Double m_last;
  public Double m_open;
  public Double m_change;
  public Double m_changePr;
  public Long m_volume;
  public StockData(String symbol, String name, double last, double open,
      double change, double changePr, long volume) {
    m_symbol = symbol;
    m_name = name;
    m_last = new Double(last);
    m_open = new Double(open);
    m_change = new Double(change);
    m_changePr = new Double(changePr);
    m_volume = new Long(volume);
  }
}
class ColumnData {
  public String m_title;
  public int m_width;
  public int m_alignment;
  public ColumnData(String title, int width, int alignment) {
    m_title = title;
    m_width = width;
    m_alignment = alignment;
  }
}
class StockTableData extends AbstractTableModel {
  static final public ColumnData m_columns[] = {
      new ColumnData("Symbol", 100, JLabel.LEFT),
      new ColumnData("Name", 160, JLabel.LEFT),
      new ColumnData("Last", 100, JLabel.RIGHT),
      new ColumnData("Open", 100, JLabel.RIGHT),
      new ColumnData("Change", 100, JLabel.RIGHT),
      new ColumnData("Change %", 100, JLabel.RIGHT),
      new ColumnData("Volume", 100, JLabel.RIGHT) };
  protected SimpleDateFormat m_frm;
  protected Vector m_vector;
  protected Date m_date;
  public StockTableData() {
    m_frm = new SimpleDateFormat("MM/dd/yyyy");
    m_vector = new Vector();
    setDefaultData();
  }
  public void setDefaultData() {
    try {
      m_date = m_frm.parse("4/6/1999");
    } catch (java.text.ParseException ex) {
      m_date = null;
    }
    m_vector.removeAllElements();
    m_vector.addElement(new StockData("ORCL", "Oracle Corp.", 23.6875,
        25.375, -1.6875, -6.42, 24976600));
    m_vector.addElement(new StockData("EGGS", "Egghead.ru", 17.25,
        17.4375, -0.1875, -1.43, 2146400));
    m_vector.addElement(new StockData("T", "AT&T", 65.1875, 66, -0.8125,
        -0.10, 554000));
    m_vector.addElement(new StockData("LU", "Lucent Technology", 64.625,
        59.9375, 4.6875, 9.65, 29856300));
    m_vector.addElement(new StockData("FON", "Sprint", 104.5625, 106.375,
        -1.8125, -1.82, 1135100));
    m_vector.addElement(new StockData("ENML", "Enamelon Inc.", 4.875, 5,
        -0.125, 0, 35900));
    m_vector.addElement(new StockData("CPQ", "Compaq Computers", 30.875,
        31.25, -0.375, -2.18, 11853900));
    m_vector.addElement(new StockData("MSFT", "Microsoft Corp.", 94.0625,
        95.1875, -1.125, -0.92, 19836900));
    m_vector.addElement(new StockData("DELL", "Dell Computers", 46.1875,
        44.5, 1.6875, 6.24, 47310000));
    m_vector.addElement(new StockData("SUNW", "Sun Microsystems", 140.625,
        130.9375, 10, 10.625, 17734600));
    m_vector.addElement(new StockData("IBM", "Intl. Bus. Machines", 183,
        183.125, -0.125, -0.51, 4371400));
    m_vector.addElement(new StockData("HWP", "Hewlett-Packard", 70,
        71.0625, -1.4375, -2.01, 2410700));
    m_vector.addElement(new StockData("UIS", "Unisys Corp.", 28.25, 29,
        -0.75, -2.59, 2576200));
    m_vector.addElement(new StockData("SNE", "Sony Corp.", 96.1875, 95.625,
        1.125, 1.18, 330600));
    m_vector.addElement(new StockData("NOVL", "Novell Inc.", 24.0625,
        24.375, -0.3125, -3.02, 6047900));
    m_vector.addElement(new StockData("HIT", "Hitachi, Ltd.", 78.5, 77.625,
        0.875, 1.12, 49400));
  }
  public int getRowCount() {
    return m_vector == null ? 0 : m_vector.size();
  }
  public int getColumnCount() {
    return m_columns.length;
  }
  public String getColumnName(int column) {
    return m_columns[column].m_title;
  }
  public boolean isCellEditable(int nRow, int nCol) {
    return false;
  }
  public Object getValueAt(int nRow, int nCol) {
    if (nRow < 0 || nRow >= getRowCount())
      return "";
    StockData row = (StockData) m_vector.elementAt(nRow);
    switch (nCol) {
    case 0:
      return row.m_symbol;
    case 1:
      return row.m_name;
    case 2:
      return row.m_last;
    case 3:
      return row.m_open;
    case 4:
      return row.m_change;
    case 5:
      return row.m_changePr;
    case 6:
      return row.m_volume;
    }
    return "";
  }
  public String getTitle() {
    if (m_date == null)
      return "Stock Quotes";
    return "Stock Quotes at " + m_frm.format(m_date);
  }
}





Table model is based on call back

    
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
public class ExampleTableModel extends AbstractTableModel {
  String columnName[] = { "description", "data", "boolean values" };
  Class columnType[] = { String.class, String.class, Boolean.class };
  Object table[][] = { { "this is line", "data", new Boolean(true) },
      { "this is line", "data", new Boolean(false) },
      { "this is line", "data", new Boolean(true) },
      { "this is line", "data", new Boolean(false) },
      { "this is line", "data", new Boolean(true) },
      { "this is line", "data", new Boolean(false) },
      { "this is line", "data", new Boolean(true) },
      { "this is line", "data", new Boolean(false) },
      { "this is line", "data", new Boolean(true) } };
  public int getColumnCount() {
    return table[0].length;
  }
  public int getRowCount() {
    return table.length;
  }
  public Object getValueAt(int r, int c) {
    return table[r][c];
  }
  public String getColumnName(int column) {
    return columnName[column];
  }
  public Class getColumnClass(int c) {
    return columnType[c];
  }
  public boolean isCellEditable(int r, int c) {
    return false;
  }
  public void setValueAt(Object aValue, int r, int c) {
  }
  public static void main(String[] arg){
    JFrame f = new JFrame();
    f.getContentPane().add(new JScrollPane(new JTable(new ExampleTableModel())));
    f.setSize(300,300);
    f.show();
  }
}





TableSorter extends AbstractTableModel

    
/*
This file is part of BORG.
    BORG is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.
    BORG is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    You should have received a copy of the GNU General Public License
    along with BORG; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
Copyright 2003 by Mike Berger
 */

import java.awt.Color;
import java.awt.ruponent;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.ruparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.swing.Icon;
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.SwingConstants;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;
/**
 * TableSorter is a decorator for TableModels; adding sorting
 * functionality to a supplied TableModel. TableSorter does
 * not store or copy the data in its TableModel; instead it maintains
 * a map from the row indexes of the view to the row indexes of the
 * model. As requests are made of the sorter (like getValueAt(row, col))
 * they are passed to the underlying model after the row numbers
 * have been translated via the internal mapping array. This way,
 * the TableSorter appears to hold another copy of the table
 * with the rows in a different order.
 * <p/>
 * TableSorter registers itself as a listener to the underlying model,
 * just as the JTable itself would. Events recieved from the model
 * are examined, sometimes manipulated (typically widened), and then
 * passed on to the TableSorter"s listeners (typically the JTable).
 * If a change to the model has invalidated the order of TableSorter"s
 * rows, a note of this is made and the sorter will resort the
 * rows the next time a value is requested.
 * <p/>
 * When the tableHeader property is set, either by using the
 * setTableHeader() method or the two argument constructor, the
 * table header may be used as a complete UI for TableSorter.
 * The default renderer of the tableHeader is decorated with a renderer
 * that indicates the sorting status of each column. In addition,
 * a mouse listener is installed with the following behavior:
 * <ul>
 * <li>
 * Mouse-click: Clears the sorting status of all other columns
 * and advances the sorting status of that column through three
 * values: {NOT_SORTED, ASCENDING, DESCENDING} (then back to
 * NOT_SORTED again).
 * <li>
 * SHIFT-mouse-click: Clears the sorting status of all other columns
 * and cycles the sorting status of the column through the same
 * three values, in the opposite order: {NOT_SORTED, DESCENDING, ASCENDING}.
 * <li>
 * CONTROL-mouse-click and CONTROL-SHIFT-mouse-click: as above except
 * that the changes to the column do not cancel the statuses of columns
 * that are already sorting - giving a way to initiate a compound
 * sort.
 * </ul>
 * <p/>
 * This is a long overdue rewrite of a class of the same name that
 * first appeared in the swing table demos in 1997.
 * 
 * @author Philip Milne
 * @author Brendon McLean 
 * @author Dan van Enckevort
 * @author Parwinder Sekhon
 * @version 2.0 02/27/04
 */
/* updated by Mike Berger 
 * 
 * - lots didn"t work out of the box. Plus code was added to make this object
 *   compatible with the old TableSorter so the rest of the code did not have to change
 */
@SuppressWarnings("unchecked") //$NON-NLS-1$
public class TableSorter extends AbstractTableModel {
    protected TableModel tableModel;
    public static final int DESCENDING = -1;
    public static final int NOT_SORTED = 0;
    public static final int ASCENDING = 1;
    private static Directive EMPTY_DIRECTIVE = new Directive(-1, NOT_SORTED);
    public static final Comparator<Object> COMPARABLE_COMAPRATOR = new Comparator() {
        public int compare(Object o1, Object o2) {
            return ((Comparable<Object>) o1).rupareTo(o2);
        }
    };
    public static final Comparator<Object> LEXICAL_COMPARATOR = new Comparator() {
        public int compare(Object o1, Object o2) {
            return o1.toString().rupareTo(o2.toString());
        }
    };
    
    
    private Row[] viewToModel;
    private int[] modelToView;
    private JTableHeader tableHeader;

    private Map<Class, Comparator> columnComparators = new HashMap<Class, Comparator>();
    private List<Directive> sortingColumns = new ArrayList<Directive>();
    public TableSorter() {
    }
    private void clearSortingState() {
        viewToModel = null;
        modelToView = null;
    }
    public TableModel getTableModel() {
        return tableModel;
    }
    public void setTableModel(TableModel tableModel) {
        if (this.tableModel != null) {
            this.tableModel.removeTableModelListener(tableModelListener);
        }
        this.tableModel = tableModel;
        if (this.tableModel != null) {
            this.tableModel.addTableModelListener(tableModelListener);
        }
        clearSortingState();
        fireTableStructureChanged();
    }
    public JTableHeader getTableHeader() {
        return tableHeader;
    }
    public void setTableHeader(JTableHeader tableHeader) {
        if (this.tableHeader != null) {
            this.tableHeader.removeMouseListener(mouseListener_);
            TableCellRenderer defaultRenderer = this.tableHeader.getDefaultRenderer();
            if (defaultRenderer instanceof SortableHeaderRenderer) {
                this.tableHeader.setDefaultRenderer(((SortableHeaderRenderer) defaultRenderer).tableCellRenderer);
            }
        }
        this.tableHeader = tableHeader;
        if (this.tableHeader != null) {
            this.tableHeader.addMouseListener(mouseListener_);
            this.tableHeader.setDefaultRenderer(
                    new SortableHeaderRenderer(this.tableHeader.getDefaultRenderer()));
        }
    }
    public boolean isSorting() {
        return sortingColumns.size() != 0;
    }
    private Directive getDirective(int column) {
        for (int i = 0; i < sortingColumns.size(); i++) {
            Directive directive = sortingColumns.get(i);
            if (directive.column == column) {
                return directive;
            }
        }
        return EMPTY_DIRECTIVE;
    }
    public int getSortingStatus(int column) {
        return getDirective(column).direction;
    }
    private void sortingStatusChanged() {
        clearSortingState();
        fireTableDataChanged();
        if (tableHeader != null) {
            tableHeader.repaint();
        }
    }
    public void setSortingStatus(int column, int status) {
        Directive directive = getDirective(column);
        if (directive != EMPTY_DIRECTIVE) {
            sortingColumns.remove(directive);
        }
        if (status != NOT_SORTED) {
            sortingColumns.add(new Directive(column, status));
        }
        sortingStatusChanged();
    }
    protected Icon getHeaderRendererIcon(int column, int size) {
        Directive directive = getDirective(column);
        if (directive == EMPTY_DIRECTIVE) {
            return null;
        }
        return new Arrow(directive.direction == DESCENDING, size, sortingColumns.indexOf(directive));
    }
    private void cancelSorting() {
        sortingColumns.clear();
        sortingStatusChanged();
    }
/* TODO UCdetector: Remove unused code: 
    public void setColumnComparator(Class type, Comparator comparator) {
        if (comparator == null) {
            columnComparators.remove(type);
        } else {
            columnComparators.put(type, comparator);
        }
    }
*/
    protected Comparator<Object> getComparator(int column) {
        Class columnType = tableModel.getColumnClass(column);
        Comparator<Object> comparator = columnComparators.get(columnType);
        if (comparator != null) {
            return comparator;
        }
        if (Comparable.class.isAssignableFrom(columnType)) {
            return COMPARABLE_COMAPRATOR;
        }
        return LEXICAL_COMPARATOR;
    }
    private Row[] getViewToModel() {
        if (viewToModel == null) {
            int tableModelRowCount = tableModel.getRowCount();
            viewToModel = new Row[tableModelRowCount];
            for (int row = 0; row < tableModelRowCount; row++) {
                viewToModel[row] = new Row(row);
            }
            if (isSorting()) {
                Arrays.sort(viewToModel);
            }
        }
        return viewToModel;
    }
    public int modelIndex(int viewIndex) {
        return getViewToModel()[viewIndex].modelIndex;
    }
    private int[] getModelToView() {
        if (modelToView == null) {
            int n = getViewToModel().length;
            modelToView = new int[n];
            for (int i = 0; i < n; i++) {
                modelToView[modelIndex(i)] = i;
            }
        }
        return modelToView;
    }
    // TableModel interface methods 
    public int getRowCount() {
        return (tableModel == null) ? 0 : tableModel.getRowCount();
    }
    public int getColumnCount() {
        return (tableModel == null) ? 0 : tableModel.getColumnCount();
    }
    public String getColumnName(int column) {
        return tableModel.getColumnName(column);
    }
    public Class getColumnClass(int column) {
        return tableModel.getColumnClass(column);
    }
    public boolean isCellEditable(int row, int column) {
        return tableModel.isCellEditable(modelIndex(row), column);
    }
    public Object getValueAt(int row, int column) {
        return tableModel.getValueAt(modelIndex(row), column);
    }
    public void setValueAt(Object aValue, int row, int column) {
        tableModel.setValueAt(aValue, modelIndex(row), column);
    }
    // Helper classes
    
    private class Row implements Comparable {
        private int modelIndex;
        public Row(int index) {
            this.modelIndex = index;
        }
        public int compareTo(Object o) {
            int row1 = modelIndex;
            int row2 = ((Row) o).modelIndex;
            for (Iterator<Directive> it = sortingColumns.iterator(); it.hasNext();) {
                Directive directive = it.next();
                int column = directive.column;
                Object o1 = tableModel.getValueAt(row1, column);
                Object o2 = tableModel.getValueAt(row2, column);
                int comparison = 0;
                // Define null less than everything, except null.
                if (o1 == null && o2 == null) {
                    comparison = 0;
                } else if (o1 == null) {
                    comparison = -1;
                } else if (o2 == null) {
                    comparison = 1;
                } else {
                    comparison = getComparator(column).rupare(o1, o2);
                }
                if (comparison != 0) {
                    return directive.direction == DESCENDING ? -comparison : comparison;
                }
            }
            return 0;
        }
    }
    private TableModelListener tableModelListener = new TableModelListener (){
        public void tableChanged(TableModelEvent e) {
            // If we"re not sorting by anything, just pass the event along.             
            if (!isSorting()) {
                clearSortingState();
                fireTableChanged(e);
                return;
            }
                
            // If the table structure has changed, cancel the sorting; the             
            // sorting columns may have been either moved or deleted from             
            // the model. 
            if (e.getFirstRow() == TableModelEvent.HEADER_ROW) {
                cancelSorting();
                fireTableChanged(e);
                return;
            }
            // We can map a cell event through to the view without widening             
            // when the following conditions apply: 
            // 
            // a) all the changes are on one row (e.getFirstRow() == e.getLastRow()) and, 
            // b) all the changes are in one column (column != TableModelEvent.ALL_COLUMNS) and,
            // c) we are not sorting on that column (getSortingStatus(column) == NOT_SORTED) and, 
            // d) a reverse lookup will not trigger a sort (modelToView != null)
            //
            // Note: INSERT and DELETE events fail this test as they have column == ALL_COLUMNS.
            // 
            // The last check, for (modelToView != null) is to see if modelToView 
            // is already allocated. If we don"t do this check; sorting can become 
            // a performance bottleneck for applications where cells  
            // change rapidly in different parts of the table. If cells 
            // change alternately in the sorting column and then outside of             
            // it this class can end up re-sorting on alternate cell updates - 
            // which can be a performance problem for large tables. The last 
            // clause avoids this problem. 
            int column = e.getColumn();
            if (e.getFirstRow() == e.getLastRow()
                    && column != TableModelEvent.ALL_COLUMNS
                    && getSortingStatus(column) == NOT_SORTED
                    && modelToView != null) {
                int viewIndex = getModelToView()[e.getFirstRow()];
                fireTableChanged(new TableModelEvent(TableSorter.this, 
                                                     viewIndex, viewIndex, 
                                                     column, e.getType()));
                return;
            }
            // Something has happened to the data that may have invalidated the row order. 
            clearSortingState();
            fireTableDataChanged();
            return;
        }
    };
    private MouseAdapter mouseListener_ = new MouseAdapter (){
        public void mouseClicked(MouseEvent e) {
            JTableHeader h = (JTableHeader) e.getSource();
            TableColumnModel columnModel = h.getColumnModel();
            int viewColumn = columnModel.getColumnIndexAtX(e.getX());
            int column = columnModel.getColumn(viewColumn).getModelIndex();
            if (column != -1) {
                int status = getSortingStatus(column);
                if (!e.isControlDown()) {
                    cancelSorting();
                }
                // Cycle the sorting states through {NOT_SORTED, ASCENDING, DESCENDING} or 
                // {NOT_SORTED, DESCENDING, ASCENDING} depending on whether shift is pressed. 
                status = status + (e.isShiftDown() ? -1 : 1);
                status = (status + 4) % 3 - 1; // signed mod, returning {-1, 0, 1}
                setSortingStatus(column, status);
            }
        }
    };
    
    private static class Arrow implements Icon {
        private boolean descending;
        private int size;
        private int priority;
        public Arrow(boolean descending, int size, int priority) {
            this.descending = descending;
            this.size = size;
            this.priority = priority;
        }
        public void paintIcon(Component c, Graphics g, int x, int y) {
            Color color = c == null ? Color.GRAY : c.getBackground();             
            // In a compound sort, make each succesive triangle 20% 
            // smaller than the previous one. 
            int dx = (int)(size/2*Math.pow(0.8, priority));
            int dy = descending ? dx : -dx;
            // Align icon (roughly) with font baseline. 
            y = y + 5*size/6 + (descending ? -dy : 0);
            int shift = descending ? 1 : -1;
            g.translate(x, y);
            // Right diagonal. 
            g.setColor(color.darker());
            g.drawLine(dx / 2, dy, 0, 0);
            g.drawLine(dx / 2, dy + shift, 0, shift);
            
            // Left diagonal. 
            g.setColor(color.brighter());
            g.drawLine(dx / 2, dy, dx, 0);
            g.drawLine(dx / 2, dy + shift, dx, shift);
            
            // Horizontal line. 
            if (descending) {
                g.setColor(color.darker().darker());
            } else {
                g.setColor(color.brighter().brighter());
            }
            g.drawLine(dx, 0, 0, 0);
            g.setColor(color);
            g.translate(-x, -y);
        }
        public int getIconWidth() {
            return size;
        }
        public int getIconHeight() {
            return size;
        }
    }
    private class SortableHeaderRenderer implements TableCellRenderer {
        private TableCellRenderer tableCellRenderer;
        public SortableHeaderRenderer(TableCellRenderer tableCellRenderer) {
            this.tableCellRenderer = tableCellRenderer;
        }
        public Component getTableCellRendererComponent(JTable table, 
                                                       Object value,
                                                       boolean isSelected, 
                                                       boolean hasFocus,
                                                       int row, 
                                                       int column) {
            Component c = tableCellRenderer.getTableCellRendererComponent(table, 
                    value, isSelected, hasFocus, row, column);
            if (c instanceof JLabel) {
                JLabel l = (JLabel) c;
                l.setHorizontalTextPosition(SwingConstants.LEFT);
                int modelColumn = table.convertColumnIndexToModel(column);
                l.setIcon(getHeaderRendererIcon(modelColumn, l.getFont().getSize()));
            }
            return c;
        }
    }
    private static class Directive {
        private int column;
        private int direction;
        public Directive(int column, int direction) {
            this.column = column;
            this.direction = direction;
        }
    }
    
    
    
    // 
    // compatibility with the old SUN TableSorter
    // 
    
    private class NewTableModel extends DefaultTableModel{
        Class [] classes_;
        boolean [] editable_;
        
        public NewTableModel( String cols[], Class classes[], boolean editable[])
        {
            super( cols, 0 );
            classes_ = classes;
            if( editable != null )
          editable_ = editable;
            else
            {
          editable_ = new boolean[cols.length];
          for(int i = 0; i < cols.length; i++)
              editable_[i] = false;
            }
        }
 
        public Class getColumnClass(int column) {
            return classes_[column];
        }
        
        public boolean isCellEditable(int rowIndex, int columnIndex)
        {
            
            return(editable_[columnIndex]);
        }
    }
    
    public TableSorter( String cols[], Class classes[], boolean editable[])
    {
        setTableModel(new NewTableModel(cols,classes, editable));
    }
    
    public TableSorter( String cols[], Class classes[])
    {
        setTableModel(new NewTableModel(cols,classes, null));
    }
    /**
     * @param table1
     */
    public void addMouseListenerToHeaderInTable(JTable table1) {
        table1.setColumnSelectionAllowed(false);
        setTableHeader(table1.getTableHeader());       
    }
    /**
     * @param ro
     */
    public void addRow(Object[] ro) {
        DefaultTableModel tm = (DefaultTableModel) getTableModel();
        tm.addRow(ro);
        fireTableDataChanged();
    }
    
    public void removeRow(int row) { // NO_UCD
        DefaultTableModel tm = (DefaultTableModel) getTableModel();
        tm.removeRow(row);
        fireTableDataChanged();
    }
    /**
     * @param event
     */
    public void tableChanged(TableModelEvent event) {
        NewTableModel tm = (NewTableModel) getTableModel();
        tm.fireTableChanged(event);
        fireTableDataChanged();
        
    }
    /**
     * @param i
     */
    public void setRowCount(int i) {
        DefaultTableModel tm = (DefaultTableModel) getTableModel();
        tm.setRowCount(i);   
        fireTableDataChanged();
    }
    /**
     * @param i
     */
    public void sortByColumn(int i) {
        setSortingStatus(i, ASCENDING);
        
    }
    /**
     * @param index
     * @return
     */
    public int getMappedIndex(int index) {      
        return( modelIndex(index));
    }
    /**
     * @return
     */
    public boolean isSorted() {
        
        return isSorting();
    }
    /**
     * 
     */
    public void sort() {
        fireTableDataChanged();
    }
}





TableSorter is a decorator for TableModels

    

import java.util.ArrayList;
import java.util.Arrays;
import java.util.ruparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.awt.Color;
import java.awt.ruponent;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.Icon;
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;
/**
 * TableSorter is a decorator for TableModels; adding sorting
 * functionality to a supplied TableModel. TableSorter does
 * not store or copy the data in its TableModel; instead it maintains
 * a map from the row indexes of the view to the row indexes of the
 * model. As requests are made of the sorter (like getValueAt(row, col))
 * they are passed to the underlying model after the row numbers
 * have been translated via the internal mapping array. This way,
 * the TableSorter appears to hold another copy of the table
 * with the rows in a different order.
 * <p/>
 * TableSorter registers itself as a listener to the underlying model,
 * just as the JTable itself would. Events recieved from the model
 * are examined, sometimes manipulated (typically widened), and then
 * passed on to the TableSorter"s listeners (typically the JTable).
 * If a change to the model has invalidated the order of TableSorter"s
 * rows, a note of this is made and the sorter will resort the
 * rows the next time a value is requested.
 * <p/>
 * When the tableHeader property is set, either by using the
 * setTableHeader() method or the two argument constructor, the
 * table header may be used as a complete UI for TableSorter.
 * The default renderer of the tableHeader is decorated with a renderer
 * that indicates the sorting status of each column. In addition,
 * a mouse listener is installed with the following behavior:
 * <ul>
 * <li>
 * Mouse-click: Clears the sorting status of all other columns
 * and advances the sorting status of that column through three
 * values: {NOT_SORTED, ASCENDING, DESCENDING} (then back to
 * NOT_SORTED again).
 * <li>
 * SHIFT-mouse-click: Clears the sorting status of all other columns
 * and cycles the sorting status of the column through the same
 * three values, in the opposite order: {NOT_SORTED, DESCENDING, ASCENDING}.
 * <li>
 * CONTROL-mouse-click and CONTROL-SHIFT-mouse-click: as above except
 * that the changes to the column do not cancel the statuses of columns
 * that are already sorting - giving a way to initiate a compound
 * sort.
 * </ul>
 * <p/>
 * This is a long overdue rewrite of a class of the same name that
 * first appeared in the swing table demos in 1997.
 *
 * @author Philip Milne
 * @author Brendon McLean
 * @author Dan van Enckevort
 * @author Parwinder Sekhon
 * @version 2.0 02/27/04
 */
public class TableSorter extends AbstractTableModel {
    protected TableModel           tableModel;
    public static final int        DESCENDING            = -1;
    public static final int        NOT_SORTED            = 0;
    public static final int        ASCENDING             = 1;
    private static Directive EMPTY_DIRECTIVE = new Directive(-1, NOT_SORTED);
    public static final Comparator COMPARABLE_COMPARATOR = new Comparator() {
        public int compare(Object o1, Object o2) {
            if (o1 == o2) {
                return 0;
            }
            if (o1 == null) {
                if (o2 == null) {
                    return 0;
                }
                return -1;
            }
            if (o2 == null) {
                return 1;
            }
            return ((Comparable) o1).rupareTo(o2);
        }
    };
    public static final Comparator LEXICAL_COMPARATOR = new Comparator() {
        public int compare(Object o1, Object o2) {
            return o1.toString().rupareTo(o2.toString());
        }
    };
    private Row[]              viewToModel;
    private int[]              modelToView;
    private JTableHeader       tableHeader;
    private MouseListener      mouseListener;
    private TableModelListener tableModelListener;
    private Map                columnComparators = new HashMap();
    private List               sortingColumns    = new ArrayList();
    public TableSorter() {
        this.mouseListener      = new MouseHandler();
        this.tableModelListener = new TableModelHandler();
    }
    public TableSorter(TableModel tableModel) {
        this();
        setTableModel(tableModel);
    }
    public TableSorter(TableModel tableModel, JTableHeader tableHeader) {
        this();
        setTableHeader(tableHeader);
        setTableModel(tableModel);
    }
    private void clearSortingState() {
        viewToModel = null;
        modelToView = null;
    }
    public TableModel getTableModel() {
        return tableModel;
    }
    public void setTableModel(TableModel tableModel) {
        if (this.tableModel != null) {
            this.tableModel.removeTableModelListener(tableModelListener);
        }
        this.tableModel = tableModel;
        if (this.tableModel != null) {
            this.tableModel.addTableModelListener(tableModelListener);
        }
        clearSortingState();
        fireTableStructureChanged();
    }
    public JTableHeader getTableHeader() {
        return tableHeader;
    }
    public void setTableHeader(JTableHeader tableHeader) {
        if (this.tableHeader != null) {
            this.tableHeader.removeMouseListener(mouseListener);
            TableCellRenderer defaultRenderer =
                this.tableHeader.getDefaultRenderer();
            if (defaultRenderer instanceof SortableHeaderRenderer) {
                this.tableHeader.setDefaultRenderer(
                    ((SortableHeaderRenderer) defaultRenderer)
                        .tableCellRenderer);
            }
        }
        this.tableHeader = tableHeader;
        if (this.tableHeader != null) {
            this.tableHeader.addMouseListener(mouseListener);
            this.tableHeader.setDefaultRenderer(
                new SortableHeaderRenderer(
                    this.tableHeader.getDefaultRenderer()));
        }
    }
    public boolean isSorting() {
        return sortingColumns.size() != 0;
    }
    private Directive getDirective(int column) {
        for (int i = 0; i < sortingColumns.size(); i++) {
            Directive directive = (Directive) sortingColumns.get(i);
            if (directive.column == column) {
                return directive;
            }
        }
        return EMPTY_DIRECTIVE;
    }
    public int getSortingStatus(int column) {
        return getDirective(column).direction;
    }
    private void sortingStatusChanged() {
        clearSortingState();
        fireTableDataChanged();
        if (tableHeader != null) {
            tableHeader.repaint();
        }
    }
    public void setSortingStatus(int column, int status) {
        Directive directive = getDirective(column);
        if (directive != EMPTY_DIRECTIVE) {
            sortingColumns.remove(directive);
        }
        if (status != NOT_SORTED) {
            sortingColumns.add(new Directive(column, status));
        }
        sortingStatusChanged();
    }
    protected Icon getHeaderRendererIcon(int column, int size) {
        Directive directive = getDirective(column);
        if (directive == EMPTY_DIRECTIVE) {
            return null;
        }
        return new Arrow(directive.direction == DESCENDING, size,
                         sortingColumns.indexOf(directive));
    }
    private void cancelSorting() {
        sortingColumns.clear();
        sortingStatusChanged();
    }
    public void setColumnComparator(Class type, Comparator comparator) {
        if (comparator == null) {
            columnComparators.remove(type);
        } else {
            columnComparators.put(type, comparator);
        }
    }
    protected Comparator getComparator(int column) {
        Class columnType = tableModel.getColumnClass(column);
        Comparator comparator =
            (Comparator) columnComparators.get(columnType);
        if (comparator != null) {
            return comparator;
        }
        if (Comparable.class.isAssignableFrom(columnType)) {
            return COMPARABLE_COMPARATOR;
        }
        return LEXICAL_COMPARATOR;
    }
    private Row[] getViewToModel() {
        if (viewToModel == null) {
            int tableModelRowCount = tableModel.getRowCount();
            viewToModel = new Row[tableModelRowCount];
            for (int row = 0; row < tableModelRowCount; row++) {
                viewToModel[row] = new Row(row);
            }
            if (isSorting()) {
                Arrays.sort(viewToModel);
            }
        }
        return viewToModel;
    }
    public int modelIndex(int viewIndex) {
        return getViewToModel()[viewIndex].modelIndex;
    }
    private int[] getModelToView() {
        if (modelToView == null) {
            int n = getViewToModel().length;
            modelToView = new int[n];
            for (int i = 0; i < n; i++) {
                modelToView[modelIndex(i)] = i;
            }
        }
        return modelToView;
    }
    // TableModel interface methods
    public int getRowCount() {
        return (tableModel == null) ? 0
                                    : tableModel.getRowCount();
    }
    public int getColumnCount() {
        return (tableModel == null) ? 0
                                    : tableModel.getColumnCount();
    }
    public String getColumnName(int column) {
        return tableModel.getColumnName(column);
    }
    public Class getColumnClass(int column) {
        return tableModel.getColumnClass(column);
    }
    public boolean isCellEditable(int row, int column) {
        return tableModel.isCellEditable(modelIndex(row), column);
    }
    public Object getValueAt(int row, int column) {
        return tableModel.getValueAt(modelIndex(row), column);
    }
    public void setValueAt(Object aValue, int row, int column) {
        tableModel.setValueAt(aValue, modelIndex(row), column);
    }
    // Helper classes
    private class Row implements Comparable {
        private int modelIndex;
        public Row(int index) {
            this.modelIndex = index;
        }
        public int compareTo(Object o) {
            int row1 = modelIndex;
            int row2 = ((Row) o).modelIndex;
            for (Iterator it = sortingColumns.iterator(); it.hasNext(); ) {
                Directive directive  = (Directive) it.next();
                int       column     = directive.column;
                Object    o1         = tableModel.getValueAt(row1, column);
                Object    o2         = tableModel.getValueAt(row2, column);
                int       comparison = 0;
                // Define null less than everything, except null.
                if (o1 == null && o2 == null) {
                    comparison = 0;
                } else if (o1 == null) {
                    comparison = -1;
                } else if (o2 == null) {
                    comparison = 1;
                } else {
                    comparison = getComparator(column).rupare(o1, o2);
                }
                if (comparison != 0) {
                    return directive.direction == DESCENDING ? -comparison
                                                             : comparison;
                }
            }
            return 0;
        }
    }
    private class TableModelHandler implements TableModelListener {
        public void tableChanged(TableModelEvent e) {
            // If we"re not sorting by anything, just pass the event along.
            if (!isSorting()) {
                clearSortingState();
                fireTableChanged(e);
                return;
            }
            // If the table structure has changed, cancel the sorting; the
            // sorting columns may have been either moved or deleted from
            // the model.
            if (e == null || e.getFirstRow() == TableModelEvent.HEADER_ROW) {
                cancelSorting();
                fireTableChanged(e);
                return;
            }
            // We can map a cell event through to the view without widening
            // when the following conditions apply:
            //
            // a) all the changes are on one row (e.getFirstRow() == e.getLastRow()) and,
            // b) all the changes are in one column (column != TableModelEvent.ALL_COLUMNS) and,
            // c) we are not sorting on that column (getSortingStatus(column) == NOT_SORTED) and,
            // d) a reverse lookup will not trigger a sort (modelToView != null)
            //
            // Note: INSERT and DELETE events fail this test as they have column == ALL_COLUMNS.
            //
            // The last check, for (modelToView != null) is to see if modelToView
            // is already allocated. If we don"t do this check; sorting can become
            // a performance bottleneck for applications where cells
            // change rapidly in different parts of the table. If cells
            // change alternately in the sorting column and then outside of
            // it this class can end up re-sorting on alternate cell updates -
            // which can be a performance problem for large tables. The last
            // clause avoids this problem.
            int column = e.getColumn();
            if (e.getFirstRow() == e.getLastRow()
                    && column != TableModelEvent.ALL_COLUMNS
                    && getSortingStatus(column) == NOT_SORTED
                    && modelToView != null) {
                int viewIndex = getModelToView()[e.getFirstRow()];
                fireTableChanged(new TableModelEvent(TableSorter.this,
                                                     viewIndex, viewIndex,
                                                     column, e.getType()));
                return;
            }
            // Something has happened to the data that may have invalidated the row order.
            clearSortingState();
            fireTableDataChanged();
            return;
        }
    }
    private class MouseHandler extends MouseAdapter {
        public void mouseClicked(MouseEvent e) {
            JTableHeader     h           = (JTableHeader) e.getSource();
            TableColumnModel columnModel = h.getColumnModel();
            int viewColumn = columnModel.getColumnIndexAtX(e.getX());
            int column = columnModel.getColumn(viewColumn).getModelIndex();
            if (column != -1) {
                int status = getSortingStatus(column);
                if (!e.isControlDown()) {
                    cancelSorting();
                }
                // Cycle the sorting states through {NOT_SORTED, ASCENDING, DESCENDING} or
                // {NOT_SORTED, DESCENDING, ASCENDING} depending on whether shift is pressed.
                status = status + (e.isShiftDown() ? -1
                                                   : 1);
                status = (status + 4) % 3 - 1;    // signed mod, returning {-1, 0, 1}
                setSortingStatus(column, status);
            }
        }
    }
    private static class Arrow implements Icon {
        private boolean descending;
        private int     size;
        private int     priority;
        public Arrow(boolean descending, int size, int priority) {
            this.descending = descending;
            this.size       = size;
            this.priority   = priority;
        }
        public void paintIcon(Component c, Graphics g, int x, int y) {
            Color color = c == null ? Color.gray
                                    : c.getBackground();
            // In a compound sort, make each succesive triangle 20%
            // smaller than the previous one.
            int dx = (int) (size / 2 * Math.pow(0.8, priority));
            int dy = descending ? dx
                                : -dx;
            // Align icon (roughly) with font baseline.
            y = y + 5 * size / 6 + (descending ? -dy
                                               : 0);
            int shift = descending ? 1
                                   : -1;
            g.translate(x, y);
            // Right diagonal.
            g.setColor(color.darker());
            g.drawLine(dx / 2, dy, 0, 0);
            g.drawLine(dx / 2, dy + shift, 0, shift);
            // Left diagonal.
            g.setColor(color.brighter());
            g.drawLine(dx / 2, dy, dx, 0);
            g.drawLine(dx / 2, dy + shift, dx, shift);
            // Horizontal line.
            if (descending) {
                g.setColor(color.darker().darker());
            } else {
                g.setColor(color.brighter().brighter());
            }
            g.drawLine(dx, 0, 0, 0);
            g.setColor(color);
            g.translate(-x, -y);
        }
        public int getIconWidth() {
            return size;
        }
        public int getIconHeight() {
            return size;
        }
    }
    private class SortableHeaderRenderer implements TableCellRenderer {
        private TableCellRenderer tableCellRenderer;
        public SortableHeaderRenderer(TableCellRenderer tableCellRenderer) {
            this.tableCellRenderer = tableCellRenderer;
        }
        public Component getTableCellRendererComponent(JTable table,
                Object value, boolean isSelected, boolean hasFocus, int row,
                int column) {
            Component c =
                tableCellRenderer.getTableCellRendererComponent(table, value,
                    isSelected, hasFocus, row, column);
            if (c instanceof JLabel) {
                JLabel l = (JLabel) c;
                l.setHorizontalTextPosition(JLabel.LEFT);
                int modelColumn = table.convertColumnIndexToModel(column);
                l.setIcon(getHeaderRendererIcon(modelColumn,
                                                l.getFont().getSize()));
            }
            return c;
        }
    }
    private static class Directive {
        private int column;
        private int direction;
        public Directive(int column, int direction) {
            this.column    = column;
            this.direction = direction;
        }
    }
}





Table with a custom TableModel

    
/* From http://java.sun.ru/docs/books/tutorial/index.html */
/*
 * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * -Redistribution of source code must retain the above copyright notice, this
 *  list of conditions and the following disclaimer.
 *
 * -Redistribution in binary form must reproduce the above copyright notice,
 *  this list of conditions and the following disclaimer in the documentation
 *  and/or other materials provided with the distribution.
 *
 * Neither the name of Sun Microsystems, Inc. or the names of contributors may
 * be used to endorse or promote products derived from this software without
 * specific prior written permission.
 *
 * This software is provided "AS IS," without a warranty of any kind. ALL
 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
 * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
 * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN")
 * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
 * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
 * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
 * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
 * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
 * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
 * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 *
 * You acknowledge that this software is not designed, licensed or intended
 * for use in the design, construction, operation or maintenance of any
 * nuclear facility.
 */
/*
 * TableDemo.java is a 1.4 application that requires no other files.
 */
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
import java.awt.Dimension;
import java.awt.GridLayout;
/**
 * TableDemo is just like SimpleTableDemo, except that it uses a custom
 * TableModel.
 */
public class TableDemo extends JPanel {
  private boolean DEBUG = false;
  public TableDemo() {
    super(new GridLayout(1, 0));
    JTable table = new JTable(new MyTableModel());
    table.setPreferredScrollableViewportSize(new Dimension(500, 70));
    //Create the scroll pane and add the table to it.
    JScrollPane scrollPane = new JScrollPane(table);
    //Add the scroll pane to this panel.
    add(scrollPane);
  }
  class MyTableModel extends AbstractTableModel {
    private String[] columnNames = { "First Name", "Last Name", "Sport",
        "# of Years", "Vegetarian" };
    private Object[][] data = {
        { "Mary", "Campione", "Snowboarding", new Integer(5),
            new Boolean(false) },
        { "Alison", "Huml", "Rowing", new Integer(3), new Boolean(true) },
        { "Kathy", "Walrath", "Knitting", new Integer(2),
            new Boolean(false) },
        { "Sharon", "Zakhour", "Speed reading", new Integer(20),
            new Boolean(true) },
        { "Philip", "Milne", "Pool", new Integer(10),
            new Boolean(false) } };
    public int getColumnCount() {
      return columnNames.length;
    }
    public int getRowCount() {
      return data.length;
    }
    public String getColumnName(int col) {
      return columnNames[col];
    }
    public Object getValueAt(int row, int col) {
      return data[row][col];
    }
    /*
     * JTable uses this method to determine the default renderer/ editor for
     * each cell. If we didn"t implement this method, then the last column
     * would contain text ("true"/"false"), rather than a check box.
     */
    public Class getColumnClass(int c) {
      return getValueAt(0, c).getClass();
    }
    /*
     * Don"t need to implement this method unless your table"s editable.
     */
    public boolean isCellEditable(int row, int col) {
      //Note that the data/cell address is constant,
      //no matter where the cell appears onscreen.
      if (col < 2) {
        return false;
      } else {
        return true;
      }
    }
    /*
     * Don"t need to implement this method unless your table"s data can
     * change.
     */
    public void setValueAt(Object value, int row, int col) {
      if (DEBUG) {
        System.out.println("Setting value at " + row + "," + col
            + " to " + value + " (an instance of "
            + value.getClass() + ")");
      }
      data[row][col] = value;
      fireTableCellUpdated(row, col);
      if (DEBUG) {
        System.out.println("New value of data:");
        printDebugData();
      }
    }
    private void printDebugData() {
      int numRows = getRowCount();
      int numCols = getColumnCount();
      for (int i = 0; i < numRows; i++) {
        System.out.print("    row " + i + ":");
        for (int j = 0; j < numCols; j++) {
          System.out.print("  " + data[i][j]);
        }
        System.out.println();
      }
      System.out.println("--------------------------");
    }
  }
  /**
   * Create the GUI and show it. For thread safety, this method should be
   * invoked from the event-dispatching thread.
   */
  private static void createAndShowGUI() {
    //Make sure we have nice window decorations.
    JFrame.setDefaultLookAndFeelDecorated(true);
    //Create and set up the window.
    JFrame frame = new JFrame("TableDemo");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    //Create and set up the content pane.
    TableDemo newContentPane = new TableDemo();
    newContentPane.setOpaque(true); //content panes must be opaque
    frame.setContentPane(newContentPane);
    //Display the window.
    frame.pack();
    frame.setVisible(true);
  }
  public static void main(String[] args) {
    //Schedule a job for the event-dispatching thread:
    //creating and showing this application"s GUI.
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        createAndShowGUI();
      }
    });
  }
}





Use model to control the Editable Columns

    
/*
Definitive Guide to Swing for Java 2, Second Edition
By John Zukowski     
ISBN: 1-893115-78-X
Publisher: APress
*/
import java.awt.BorderLayout;
import java.util.Date;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableModel;
public class EditableColumn {
  public static void main(String args[]) {
    TableModel model = new AbstractTableModel() {
      Icon icon1 = new ImageIcon("TreeCollapsed.gif");
      Icon icon2 = new ImageIcon("TreeExpanded.gif");
      Object rowData[][] = {
          { new Integer(1), "ichi", Boolean.TRUE,
              new Date("01/01/2000"), icon1 },
          { new Integer(2), "ni", Boolean.TRUE,
              new Date("04/15/1999"), icon2 },
          { new Integer(3), "san", Boolean.FALSE,
              new Date("12/07/1941"), icon2 },
          { new Integer(4), "shi", Boolean.TRUE,
              new Date("02/29/2000"), icon1 },
          { new Integer(5), "go", Boolean.FALSE,
              new Date("05/23/1995"), icon1 }, };
      String columnNames[] = { "English", "Japanese", "Boolean", "Date",
          "ImageIcon" };
      public int getColumnCount() {
        return columnNames.length;
      }
      public String getColumnName(int column) {
        return columnNames[column];
      }
      public int getRowCount() {
        return rowData.length;
      }
      public Object getValueAt(int row, int column) {
        return rowData[row][column];
      }
      public Class getColumnClass(int column) {
        return (getValueAt(0, column).getClass());
      }
      public void setValueAt(Object value, int row, int column) {
        rowData[row][column] = value;
      }
      public boolean isCellEditable(int row, int column) {
        return (column != 4);
      }
    };
    JFrame frame = new JFrame("Column Renderer Table");
    JTable table = new JTable(model);
    JScrollPane scrollPane = new JScrollPane(table);
    frame.getContentPane().add(scrollPane, BorderLayout.CENTER);
    frame.setSize(400, 150);
    frame.setVisible(true);
  }
}