Java/Swing JFC/Table Model

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

Содержание

AbstractTableModel backed by Hashtable

   <source lang="java">
   

/* 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);
   }
 }

}



 </source>
   
  
 
  



Add a column without affecting existing columns

   <source lang="java">
  

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" });
 }

}


 </source>
   
  
 
  



Add a column with values.

   <source lang="java">
  

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" });
 }

}


 </source>
   
  
 
  



A JTable class using default table models and a convenience constructor

   <source lang="java">
   

//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);
 }

}



 </source>
   
  
 
  



Append a row to a table through DefaultTableModel at specified row

   <source lang="java">
  

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);
 }

}


 </source>
   
  
 
  



Appending a Column to a JTable Component using DefaultTableModel

   <source lang="java">
  

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");
 }

}


 </source>
   
  
 
  



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

   <source lang="java">
 

/*

* 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 true if the data is sorted in ascending order, and
    * false otherwise.
    *
    * @return true if the data is sorted in ascending order, and
    *         false 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.
*

* 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); } } </source>

Bean Property Table Model

   <source lang="java">
   

/*

* 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 Vector containing the cells for the line in
  *      the table. Element zero the first cell etc. Return
  *      null if this property is not 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);
   }
 }

}



 </source>
   
  
 
  



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

   <source lang="java">
  

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;
 }

}


 </source>
   
  
 
  



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

   <source lang="java">
  

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();
 }

}


 </source>
   
  
 
  



Copy (clone) the data from the second row

   <source lang="java">
  

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);
 }

}


 </source>
   
  
 
  



Copy data from a table to a list

   <source lang="java">
  

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);
 }

}


 </source>
   
  
 
  



Creating simple JTable using AbstractTableModel

   <source lang="java">
  

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;
 }

}


 </source>
   
  
 
  



Custom model, POJO and JTable

   <source lang="java">
   

/* 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);
 }

}



 </source>
   
  
 
  



Custom table model, File data based Model

   <source lang="java">
   

/* 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);
 }

}



 </source>
   
  
 
  



Disable autoCreateColumnsFromModel

   <source lang="java">
  

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);
 }

}


 </source>
   
  
 
  



extends AbstractTableModel to create custom model

   <source lang="java">
   

/* 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);
 }

}



 </source>
   
  
 
  



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

   <source lang="java">
   

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);
 }

}



 </source>
   
  
 
  



File data Table: file name, size, type

   <source lang="java">
   

/*

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

}




 </source>
   
  
 
  



Fixed data vs dynamic data Table

   <source lang="java">
   

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);
 }

}



 </source>
   
  
 
  



Get all the table data from DefaultTableModel

   <source lang="java">
  

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);
 }

}


 </source>
   
  
 
  



Hard code data in array for TableModel

   <source lang="java">
   

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);
 }

}



 </source>
   
  
 
  



Insert a new column to a table

   <source lang="java">
  

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);
 }

}


 </source>
   
  
 
  



JTable class using default table models and a convenience

   <source lang="java">
   

/* 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);
 }

}



 </source>
   
  
 
  



Map TableModel

   <source lang="java">
   

/*

* 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



 </source>
   
  
 
  



Move the first row to the end of the table

   <source lang="java">
  

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);
 }

}


 </source>
   
  
 
  



Move the first two rows to the end of the table

   <source lang="java">
  

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);
 }

}


 </source>
   
  
 
  



Move the last row to the beginning of the table

   <source lang="java">
  

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);
 }

}


 </source>
   
  
 
  



Move the last two rows to the start of the table

   <source lang="java">
  

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);
 }

}


 </source>
   
  
 
  



Overwrite the date from the first row with DefaultTableModel

   <source lang="java">
  

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);
 }

}


 </source>
   
  
 
  



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

   <source lang="java">
   

/* 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);
   }
 }

}




 </source>
   
  
 
  



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

   <source lang="java">
   

/* 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);
   }
 }

}




 </source>
   
  
 
  



Remove the first row from a table with DefaultTableModel

   <source lang="java">
  

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);
 }

}


 </source>
   
  
 
  



Remove the first visible column without removing the underlying data

   <source lang="java">
  

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;
 }

}


 </source>
   
  
 
  



Remove the last row from a table with DefaultTableModel

   <source lang="java">
  

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);
 }

}


 </source>
   
  
 
  



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

   <source lang="java">
  

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;
   }
 }

}


 </source>
   
  
 
  



Sharing a Table Model Between JTable Components

   <source lang="java">
  

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));
 }

}


 </source>
   
  
 
  



Stocks data Table: illustrate the TableModel

   <source lang="java">
   

/* 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);
 }

}




 </source>
   
  
 
  



Table model is based on call back

   <source lang="java">
   

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();
 }

}




 </source>
   
  
 
  



TableSorter extends AbstractTableModel

   <source lang="java">
   

/* 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:
*
    *
  • * 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). *
  • * 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}. *
  • * 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. *
* <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();
   }

}



 </source>
   
  
 
  



TableSorter is a decorator for TableModels

   <source lang="java">
   

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:
*
    *
  • * 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). *
  • * 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}. *
  • * 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. *
* <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;
       }
   }

}



 </source>
   
  
 
  



Table with a custom TableModel

   <source lang="java">
   

/* 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();
     }
   });
 }

}



 </source>
   
  
 
  



Use model to control the Editable Columns

   <source lang="java">
   

/* 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);
 }

}



 </source>