Java/Swing JFC/Table Model
Версия от 18:01, 31 мая 2010; (обсуждение)
Содержание
- 1 AbstractTableModel backed by Hashtable
- 2 Add a column without affecting existing columns
- 3 Add a column with values.
- 4 A JTable class using default table models and a convenience constructor
- 5 Append a row to a table through DefaultTableModel at specified row
- 6 Appending a Column to a JTable Component using DefaultTableModel
- 7 A simple extension of JTable that supports the use of a SortableTableModel.
- 8 Bean Property Table Model
- 9 Converts a column index in the model to a visible column index
- 10 Converts a visible column index to a column index in the model.
- 11 Copy (clone) the data from the second row
- 12 Copy data from a table to a list
- 13 Creating simple JTable using AbstractTableModel
- 14 Custom model, POJO and JTable
- 15 Custom table model, File data based Model
- 16 Disable autoCreateColumnsFromModel
- 17 extends AbstractTableModel to create custom model
- 18 extends DefaultTableModel to create your own table model and build table from that
- 19 File data Table: file name, size, type
- 20 Fixed data vs dynamic data Table
- 21 Get all the table data from DefaultTableModel
- 22 Hard code data in array for TableModel
- 23 Insert a new column to a table
- 24 JTable class using default table models and a convenience
- 25 Map TableModel
- 26 Move the first row to the end of the table
- 27 Move the first two rows to the end of the table
- 28 Move the last row to the beginning of the table
- 29 Move the last two rows to the start of the table
- 30 Overwrite the date from the first row with DefaultTableModel
- 31 Paging JTable(Table) Model with an input field for dynamically altering the size of a page.
- 32 Paging or pagable JTable(Table) Model for large data set
- 33 Remove the first row from a table with DefaultTableModel
- 34 Remove the first visible column without removing the underlying data
- 35 Remove the last row from a table with DefaultTableModel
- 36 Returns the visible columns in the order that they appear in the model
- 37 Sharing a Table Model Between JTable Components
- 38 Stocks data Table: illustrate the TableModel
- 39 Table model is based on call back
- 40 TableSorter extends AbstractTableModel
- 41 TableSorter is a decorator for TableModels
- 42 Table with a custom TableModel
- 43 Use model to control the Editable Columns
AbstractTableModel backed by Hashtable
/*
Definitive Guide to Swing for Java 2, Second Edition
By John Zukowski
ISBN: 1-893115-78-X
Publisher: APress
*/
import java.awt.BorderLayout;
import java.awt.Point;
import java.util.Hashtable;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableModel;
public class SparseTest {
public static void main(String args[]) {
JFrame frame = new JFrame("Sparse Test");
String headers[] = { "English", "Japanese" };
TableModel model = new SparseTableModel(10, headers);
JTable table = new JTable(model);
model.setValueAt("one", 0, 0);
model.setValueAt("ten", 9, 0);
model.setValueAt("roku - \u516D", 5, 1);
model.setValueAt("hachi - \u516B", 8, 1);
JScrollPane scrollPane = new JScrollPane(table);
frame.getContentPane().add(scrollPane, BorderLayout.CENTER);
frame.setSize(300, 150);
frame.setVisible(true);
}
}
class SparseTableModel extends AbstractTableModel {
private Hashtable lookup;
private final int rows;
private final int columns;
private final String headers[];
public SparseTableModel(int rows, String columnHeaders[]) {
if ((rows < 0) || (columnHeaders == null)) {
throw new IllegalArgumentException(
"Invalid row count/columnHeaders");
}
this.rows = rows;
this.columns = columnHeaders.length;
headers = columnHeaders;
lookup = new Hashtable();
}
public int getColumnCount() {
return columns;
}
public int getRowCount() {
return rows;
}
public String getColumnName(int column) {
return headers[column];
}
public Object getValueAt(int row, int column) {
return lookup.get(new Point(row, column));
}
public void setValueAt(Object value, int row, int column) {
if ((rows < 0) || (columns < 0)) {
throw new IllegalArgumentException("Invalid row/column setting");
}
if ((row < rows) && (column < columns)) {
lookup.put(new Point(row, column), value);
}
}
}
Add a column without affecting existing columns
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
public class Main {
public static void main(String[] argv) throws Exception {
DefaultTableModel model = new DefaultTableModel();
JTable table = new JTable(model);
model = (DefaultTableModel) table.getModel();
TableColumn col = new TableColumn(model.getColumnCount());
// Ensure that auto-create is off
if (table.getAutoCreateColumnsFromModel()) {
throw new IllegalStateException();
}
col.setHeaderValue("Col3");
table.addColumn(col);
model.addColumn("Col3", new Object[] { "v3" });
}
}
Add a column with values.
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
public class Main {
public static void main(String[] argv) throws Exception {
DefaultTableModel model = new DefaultTableModel();
JTable table = new JTable(model);
// Add a column with values.
model.addColumn("Col2", new Object[] { "v2" });
}
}
A JTable class using default table models and a convenience constructor
//A test of the JTable class using default table models and a convenience
//constructor. Resizing and selection defaults are altered.
//
import java.awt.BorderLayout;
import java.io.File;
import java.util.Date;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
public class TableFeature extends JFrame {
String titles[] = new String[] { "Directory?", "File Name", "Read?",
"Write?", "Size", "Last Modified" };
public TableFeature() {
super("Simple JTable Test");
setSize(300, 200);
setDefaultCloseOperation(EXIT_ON_CLOSE);
File pwd = new File(".");
Object[][] stats = getFileStats(pwd);
JTable jt = new JTable(stats, titles);
jt.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
jt.setColumnSelectionAllowed(true);
JScrollPane jsp = new JScrollPane(jt);
getContentPane().add(jsp, BorderLayout.CENTER);
}
public Object[][] getFileStats(File dir) {
String files[] = dir.list();
Object[][] results = new Object[files.length][titles.length];
for (int i = 0; i < files.length; i++) {
File tmp = new File(files[i]);
results[i][0] = new Boolean(tmp.isDirectory());
results[i][1] = tmp.getName();
results[i][2] = new Boolean(tmp.canRead());
results[i][3] = new Boolean(tmp.canWrite());
results[i][4] = new Long(tmp.length());
results[i][5] = new Date(tmp.lastModified());
}
return results;
}
public static void main(String args[]) {
TableFeature tf = new TableFeature();
tf.setVisible(true);
}
}
Append a row to a table through DefaultTableModel at specified row
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
public class Main {
public static void main(String[] argv) throws Exception {
DefaultTableModel model = new DefaultTableModel();
JTable table = new JTable(model);
model.addColumn("Col1");
model.addColumn("Col2");
// Create the first row
model.insertRow(0, new Object[] { "r1" });
// Append a row
model.insertRow(model.getRowCount(), new Object[] { "r5" });
JFrame f = new JFrame();
f.setSize(300, 300);
f.add(new JScrollPane(table));
f.setVisible(true);
}
}
Appending a Column to a JTable Component using DefaultTableModel
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
public class Main {
public static void main(String[] argv) throws Exception {
DefaultTableModel model = new DefaultTableModel();
JTable table = new JTable(model);
model.addColumn("Col1");
}
}
A simple extension of JTable that supports the use of a SortableTableModel.
/*
* JCommon : a free general purpose class library for the Java(tm) platform
*
*
* (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
*
* Project Info: http://www.jfree.org/jcommon/index.html
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* [Java is a trademark or registered trademark of Sun Microsystems, Inc.
* in the United States and other countries.]
*
* ------------------
* SortableTable.java
* ------------------
* (C) Copyright 2000-2004, by Object Refinery Limited.
*
* Original Author: David Gilbert (for Object Refinery Limited);
* Contributor(s): -;
*
* $Id: SortableTable.java,v 1.5 2005/11/16 15:58:41 taqua Exp $
*
* Changes (from 26-Oct-2001)
* --------------------------
* 26-Oct-2001 : Changed package to com.jrefinery.ui.*;
* 14-Oct-2002 : Fixed errors reported by Checkstyle (DG);
*
*/
import java.awt.Color;
import java.awt.ruponent;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumnModel;
/**
* A simple extension of JTable that supports the use of a SortableTableModel.
*
* @author David Gilbert
*/
public class SortableTable extends JTable {
/** A listener for sorting. */
private SortableTableHeaderListener headerListener;
/**
* Standard constructor - builds a table for the specified model.
*
* @param model the data.
*/
public SortableTable(final SortableTableModel model) {
super(model);
final SortButtonRenderer renderer = new SortButtonRenderer();
final TableColumnModel cm = getColumnModel();
for (int i = 0; i < cm.getColumnCount(); i++) {
cm.getColumn(i).setHeaderRenderer(renderer);
}
final JTableHeader header = getTableHeader();
this.headerListener = new SortableTableHeaderListener(model, renderer);
header.addMouseListener(this.headerListener);
header.addMouseMotionListener(this.headerListener);
model.sortByColumn(0, true);
}
/**
* Changes the model for the table. Takes care of updating the header listener at the
* same time.
*
* @param model the table model.
*
*/
public void setSortableModel(final SortableTableModel model) {
super.setModel(model);
this.headerListener.setTableModel(model);
final SortButtonRenderer renderer = new SortButtonRenderer();
final TableColumnModel cm = getColumnModel();
for (int i = 0; i < cm.getColumnCount(); i++) {
cm.getColumn(i).setHeaderRenderer(renderer);
}
model.sortByColumn(0, true);
}
}
/*
* JCommon : a free general purpose class library for the Java(tm) platform
*
*
* (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
*
* Project Info: http://www.jfree.org/jcommon/index.html
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* [Java is a trademark or registered trademark of Sun Microsystems, Inc.
* in the United States and other countries.]
*
* --------------------------------
* SortableTableHeaderListener.java
* --------------------------------
* (C) Copyright 2000-2004, by Nabuo Tamemasa and Contributors.
*
* Original Author: Nabuo Tamemasa;
* Contributor(s): David Gilbert (for Object Refinery Limited);
*
* $Id: SortableTableHeaderListener.java,v 1.5 2007/11/02 17:50:36 taqua Exp $
*
* Changes (from 26-Oct-2001)
* --------------------------
* 26-Oct-2001 : Changed package to com.jrefinery.ui.*;
* 14-Oct-2002 : Fixed errors reported by Checkstyle (DG);
*
*/
/**
* Captures mouse clicks on a table header, with the intention of triggering a sort. Adapted from
* code by Nabuo Tamemasa posted on http://www.codeguru.ru.
*
* @author Nabuo Tamemasa
*/
class SortableTableHeaderListener implements MouseListener, MouseMotionListener {
/** A reference to the table model. */
private SortableTableModel model;
/** The header renderer. */
private SortButtonRenderer renderer;
/** The index of the column that is sorted - used to determine the state of the renderer. */
private int sortColumnIndex;
/**
* Standard constructor.
*
* @param model the model.
* @param renderer the renderer.
*/
public SortableTableHeaderListener(final SortableTableModel model,
final SortButtonRenderer renderer) {
this.model = model;
this.renderer = renderer;
}
/**
* Sets the table model for the listener.
*
* @param model the model.
*/
public void setTableModel(final SortableTableModel model) {
this.model = model;
}
/**
* Handle a mouse press event - if the user is NOT resizing a column and NOT dragging a column
* then give visual feedback that the column header has been pressed.
*
* @param e the mouse event.
*/
public void mousePressed(final MouseEvent e) {
final JTableHeader header = (JTableHeader) e.getComponent();
if (header.getResizingColumn() == null) { // resizing takes precedence over sorting
if (header.getDraggedDistance() < 1) { // dragging also takes precedence over sorting
final int columnIndex = header.columnAtPoint(e.getPoint());
final int modelColumnIndex
= header.getTable().convertColumnIndexToModel(columnIndex);
if (this.model.isSortable(modelColumnIndex)) {
this.sortColumnIndex = header.getTable().convertColumnIndexToModel(columnIndex);
this.renderer.setPressedColumn(this.sortColumnIndex);
header.repaint();
if (header.getTable().isEditing()) {
header.getTable().getCellEditor().stopCellEditing();
}
}
else {
this.sortColumnIndex = -1;
}
}
}
}
/**
* If the user is dragging or resizing, then we clear the sort column.
*
* @param e the mouse event.
*/
public void mouseDragged(final MouseEvent e) {
final JTableHeader header = (JTableHeader) e.getComponent();
if ((header.getDraggedDistance() > 0) || (header.getResizingColumn() != null)) {
this.renderer.setPressedColumn(-1);
this.sortColumnIndex = -1;
}
}
/**
* This event is ignored (not required).
*
* @param e the mouse event.
*/
public void mouseEntered(final MouseEvent e) {
// not required
}
/**
* This event is ignored (not required).
*
* @param e the mouse event.
*/
public void mouseClicked(final MouseEvent e) {
// not required
}
/**
* This event is ignored (not required).
*
* @param e the mouse event.
*/
public void mouseMoved(final MouseEvent e) {
// not required
}
/**
* This event is ignored (not required).
*
* @param e the mouse event.
*/
public void mouseExited(final MouseEvent e) {
// not required
}
/**
* When the user releases the mouse button, we attempt to sort the table.
*
* @param e the mouse event.
*/
public void mouseReleased(final MouseEvent e) {
final JTableHeader header = (JTableHeader) e.getComponent();
if (header.getResizingColumn() == null) { // resizing takes precedence over sorting
if (this.sortColumnIndex != -1) {
final SortableTableModel model = (SortableTableModel) header.getTable().getModel();
final boolean ascending = !model.isAscending();
model.setAscending(ascending);
model.sortByColumn(this.sortColumnIndex, ascending);
this.renderer.setPressedColumn(-1); // clear
header.repaint();
}
}
}
}
/*
* JCommon : a free general purpose class library for the Java(tm) platform
*
*
* (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
*
* Project Info: http://www.jfree.org/jcommon/index.html
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* [Java is a trademark or registered trademark of Sun Microsystems, Inc.
* in the United States and other countries.]
*
* -----------------------
* SortableTableModel.java
* -----------------------
* (C) Copyright 2000-2005, by Object Refinery Limited;
*
* Original Author: David Gilbert (for Object Refinery Limited);
* Contributor(s): -;
*
* $Id: SortableTableModel.java,v 1.6 2008/09/10 09:26:11 mungady Exp $
*
* Changes (from 26-Oct-2001)
* --------------------------
* 26-Oct-2001 : Changed package to com.jrefinery.ui.* (DG);
* 20-Nov-2001 : Made constructor protected (DG);
* 14-Oct-2002 : Fixed errors reported by Checkstyle (DG);
*
*/
/**
* The base class for a sortable table model.
*
* @author David Gilbert
*/
abstract class SortableTableModel extends AbstractTableModel {
/** The column on which the data is sorted (-1 for no sorting). */
private int sortingColumn;
/** Indicates ascending (true) or descending (false) order. */
private boolean ascending;
/**
* Constructs a sortable table model.
*/
public SortableTableModel() {
this.sortingColumn = -1;
this.ascending = true;
}
/**
* Returns the index of the sorting column, or -1 if the data is not sorted
* on any column.
*
* @return the column used for sorting.
*/
public int getSortingColumn() {
return this.sortingColumn;
}
/**
* Returns <code>true</code> if the data is sorted in ascending order, and
* <code>false</code> otherwise.
*
* @return <code>true</code> if the data is sorted in ascending order, and
* <code>false</code> otherwise.
*/
public boolean isAscending() {
return this.ascending;
}
/**
* Sets the flag that determines whether the sort order is ascending or
* descending.
*
* @param flag the flag.
*/
public void setAscending(final boolean flag) {
this.ascending = flag;
}
/**
* Sorts the table.
*
* @param column the column to sort on (zero-based index).
* @param ascending a flag to indicate ascending order or descending order.
*/
public void sortByColumn(final int column, final boolean ascending) {
if (isSortable(column)) {
this.sortingColumn = column;
}
}
/**
* Returns a flag indicating whether or not a column is sortable.
*
* @param column the column (zero-based index).
*
* @return boolean.
*/
public boolean isSortable(final int column) {
return false;
}
}
/*
* JCommon : a free general purpose class library for the Java(tm) platform
*
* (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
*
* Project Info: http://www.jfree.org/jcommon/index.html
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* [Java is a trademark or registered trademark of Sun Microsystems, Inc.
* in the United States and other countries.]
*
* -----------------------
* SortButtonRenderer.java
* -----------------------
* (C) Copyright 2000-2004, by Nobuo Tamemasa and Contributors.
*
* Original Author: Nobuo Tamemasa;
* Contributor(s): David Gilbert (for Object Refinery Limited);
* Gareth Davis;
*
* $Id: SortButtonRenderer.java,v 1.7 2008/09/10 09:26:11 mungady Exp $
*
* Changes (from 26-Oct-2001)
* --------------------------
* 26-Oct-2001 : Changed package to com.jrefinery.ui.* (DG);
* 26-Jun-2002 : Removed unnecessary import (DG);
* 14-Oct-2002 : Fixed errors reported by Checkstyle (DG);
*
*/
/**
* A table cell renderer for table headings - uses one of three JButton instances to indicate the
* sort order for the table column.
* <P>
* This class (and also BevelArrowIcon) is adapted from original code by Nobuo Tamemasa (version
* 1.0, 26-Feb-1999) posted on www.codeguru.ru.
*
* @author David Gilbert
*/
class SortButtonRenderer implements TableCellRenderer {
/**
* Useful constant indicating NO sorting.
*/
public static final int NONE = 0;
/**
* Useful constant indicating ASCENDING (that is, arrow pointing down) sorting in the table.
*/
public static final int DOWN = 1;
/**
* Useful constant indicating DESCENDING (that is, arrow pointing up) sorting in the table.
*/
public static final int UP = 2;
/**
* The current pressed column (-1 for no column).
*/
private int pressedColumn = -1;
/**
* The three buttons that are used to render the table header cells.
*/
private JButton normalButton;
/**
* The three buttons that are used to render the table header cells.
*/
private JButton ascendingButton;
/**
* The three buttons that are used to render the table header cells.
*/
private JButton descendingButton;
/**
* Used to allow the class to work out whether to use the buttuns
* or labels. Labels are required when using the aqua look and feel cos the
* buttons won"t fit.
*/
private boolean useLabels;
/**
* The normal label (only used with MacOSX).
*/
private JLabel normalLabel;
/**
* The ascending label (only used with MacOSX).
*/
private JLabel ascendingLabel;
/**
* The descending label (only used with MacOSX).
*/
private JLabel descendingLabel;
/**
* Creates a new button renderer.
*/
public SortButtonRenderer() {
this.pressedColumn = -1;
this.useLabels = UIManager.getLookAndFeel().getID().equals("Aqua");
final Border border = UIManager.getBorder("TableHeader.cellBorder");
if (this.useLabels) {
this.normalLabel = new JLabel();
this.normalLabel.setHorizontalAlignment(SwingConstants.LEADING);
this.ascendingLabel = new JLabel();
this.ascendingLabel.setHorizontalAlignment(SwingConstants.LEADING);
this.ascendingLabel.setHorizontalTextPosition(SwingConstants.LEFT);
this.ascendingLabel.setIcon(new BevelArrowIcon(BevelArrowIcon.DOWN, false, false));
this.descendingLabel = new JLabel();
this.descendingLabel.setHorizontalAlignment(SwingConstants.LEADING);
this.descendingLabel.setHorizontalTextPosition(SwingConstants.LEFT);
this.descendingLabel.setIcon(new BevelArrowIcon(BevelArrowIcon.UP, false, false));
this.normalLabel.setBorder(border);
this.ascendingLabel.setBorder(border);
this.descendingLabel.setBorder(border);
}
else {
this.normalButton = new JButton();
this.normalButton.setMargin(new Insets(0, 0, 0, 0));
this.normalButton.setHorizontalAlignment(SwingConstants.LEADING);
this.ascendingButton = new JButton();
this.ascendingButton.setMargin(new Insets(0, 0, 0, 0));
this.ascendingButton.setHorizontalAlignment(SwingConstants.LEADING);
this.ascendingButton.setHorizontalTextPosition(SwingConstants.LEFT);
this.ascendingButton.setIcon(new BevelArrowIcon(BevelArrowIcon.DOWN, false, false));
this.ascendingButton.setPressedIcon(new BevelArrowIcon(BevelArrowIcon.DOWN, false, true));
this.descendingButton = new JButton();
this.descendingButton.setMargin(new Insets(0, 0, 0, 0));
this.descendingButton.setHorizontalAlignment(SwingConstants.LEADING);
this.descendingButton.setHorizontalTextPosition(SwingConstants.LEFT);
this.descendingButton.setIcon(new BevelArrowIcon(BevelArrowIcon.UP, false, false));
this.descendingButton.setPressedIcon(new BevelArrowIcon(BevelArrowIcon.UP, false, true));
this.normalButton.setBorder(border);
this.ascendingButton.setBorder(border);
this.descendingButton.setBorder(border);
}
}
/**
* Returns the renderer component.
*
* @param table the table.
* @param value the value.
* @param isSelected selected?
* @param hasFocus focussed?
* @param row the row.
* @param column the column.
* @return the renderer.
*/
public Component getTableCellRendererComponent(final JTable table,
final Object value,
final boolean isSelected,
final boolean hasFocus,
final int row, final int column) {
if (table == null) {
throw new NullPointerException("Table must not be null.");
}
final JComponent component;
final SortableTableModel model = (SortableTableModel) table.getModel();
final int cc = table.convertColumnIndexToModel(column);
final boolean isSorting = (model.getSortingColumn() == cc);
final boolean isAscending = model.isAscending();
final JTableHeader header = table.getTableHeader();
final boolean isPressed = (cc == this.pressedColumn);
if (this.useLabels) {
final JLabel label = getRendererLabel(isSorting, isAscending);
label.setText((value == null) ? "" : value.toString());
component = label;
}
else {
final JButton button = getRendererButton(isSorting, isAscending);
button.setText((value == null) ? "" : value.toString());
button.getModel().setPressed(isPressed);
button.getModel().setArmed(isPressed);
component = button;
}
if (header != null) {
component.setForeground(header.getForeground());
component.setBackground(header.getBackground());
component.setFont(header.getFont());
}
return component;
}
/**
* Returns the correct button component.
*
* @param isSorting whether the render component represents the sort column.
* @param isAscending whether the model is ascending.
* @return either the ascending, descending or normal button.
*/
private JButton getRendererButton(final boolean isSorting, final boolean isAscending) {
if (isSorting) {
if (isAscending) {
return this.ascendingButton;
}
else {
return this.descendingButton;
}
}
else {
return this.normalButton;
}
}
/**
* Returns the correct label component.
*
* @param isSorting whether the render component represents the sort column.
* @param isAscending whether the model is ascending.
* @return either the ascending, descending or normal label.
*/
private JLabel getRendererLabel(final boolean isSorting, final boolean isAscending) {
if (isSorting) {
if (isAscending) {
return this.ascendingLabel;
}
else {
return this.descendingLabel;
}
}
else {
return this.normalLabel;
}
}
/**
* Sets the pressed column.
*
* @param column the column.
*/
public void setPressedColumn(final int column) {
this.pressedColumn = column;
}
}
/*
* JCommon : a free general purpose class library for the Java(tm) platform
*
*
* (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
*
* Project Info: http://www.jfree.org/jcommon/index.html
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* [Java is a trademark or registered trademark of Sun Microsystems, Inc.
* in the United States and other countries.]
*
* -------------------
* BevelArrowIcon.java
* -------------------
* (C) Copyright 2000-2004, by Nobuo Tamemasa and Contributors.
*
* Original Author: Nobuo Tamemasa;
* Contributor(s): David Gilbert (for Object Refinery Limited);
*
* $Id: BevelArrowIcon.java,v 1.5 2007/11/02 17:50:36 taqua Exp $
*
* Changes (from 26-Oct-2001)
* --------------------------
* 26-Oct-2001 : Changed package to com.jrefinery.ui.*;
* 13-Oct-2002 : Fixed errors reported by Checkstyle (DG);
*
*/
/**
* An arrow icon that can point up or down (usually used to indicate the sort direction in a table).
* <P>
* This class (and also SortButtonRenderer) is based on original code by Nobuo Tamemasa (version
* 1.0, 26-Feb-1999) posted on www.codeguru.ru.
*
* @author Nobuo Tamemasa
*/
class BevelArrowIcon implements Icon {
/** Constant indicating that the arrow is pointing up. */
public static final int UP = 0;
/** Constant indicating that the arrow is pointing down. */
public static final int DOWN = 1;
/** The default arrow size. */
private static final int DEFAULT_SIZE = 11;
/** Edge color 1. */
private Color edge1;
/** Edge color 2. */
private Color edge2;
/** The fill color for the arrow icon. */
private Color fill;
/** The size of the icon. */
private int size;
/** The direction that the arrow is pointing (UP or DOWN). */
private int direction;
/**
* Standard constructor - builds an icon with the specified attributes.
*
* @param direction .
* @param isRaisedView .
* @param isPressedView .
*/
public BevelArrowIcon(final int direction,
final boolean isRaisedView,
final boolean isPressedView) {
if (isRaisedView) {
if (isPressedView) {
init(UIManager.getColor("controlLtHighlight"),
UIManager.getColor("controlDkShadow"),
UIManager.getColor("controlShadow"),
DEFAULT_SIZE, direction);
}
else {
init(UIManager.getColor("controlHighlight"),
UIManager.getColor("controlShadow"),
UIManager.getColor("control"),
DEFAULT_SIZE, direction);
}
}
else {
if (isPressedView) {
init(UIManager.getColor("controlDkShadow"),
UIManager.getColor("controlLtHighlight"),
UIManager.getColor("controlShadow"),
DEFAULT_SIZE, direction);
}
else {
init(UIManager.getColor("controlShadow"),
UIManager.getColor("controlHighlight"),
UIManager.getColor("control"),
DEFAULT_SIZE, direction);
}
}
}
/**
* Standard constructor - builds an icon with the specified attributes.
*
* @param edge1 the color of edge1.
* @param edge2 the color of edge2.
* @param fill the fill color.
* @param size the size of the arrow icon.
* @param direction the direction that the arrow points.
*/
public BevelArrowIcon(final Color edge1,
final Color edge2,
final Color fill,
final int size,
final int direction) {
init(edge1, edge2, fill, size, direction);
}
/**
* Paints the icon at the specified position. Supports the Icon interface.
*
* @param c .
* @param g .
* @param x .
* @param y .
*/
public void paintIcon(final Component c,
final Graphics g,
final int x,
final int y) {
switch (this.direction) {
case DOWN: drawDownArrow(g, x, y); break;
case UP: drawUpArrow(g, x, y); break;
}
}
/**
* Returns the width of the icon. Supports the Icon interface.
*
* @return the icon width.
*/
public int getIconWidth() {
return this.size;
}
/**
* Returns the height of the icon. Supports the Icon interface.
* @return the icon height.
*/
public int getIconHeight() {
return this.size;
}
/**
* Initialises the attributes of the arrow icon.
*
* @param edge1 the color of edge1.
* @param edge2 the color of edge2.
* @param fill the fill color.
* @param size the size of the arrow icon.
* @param direction the direction that the arrow points.
*/
private void init(final Color edge1,
final Color edge2,
final Color fill,
final int size,
final int direction) {
this.edge1 = edge1;
this.edge2 = edge2;
this.fill = fill;
this.size = size;
this.direction = direction;
}
/**
* Draws the arrow pointing down.
*
* @param g the graphics device.
* @param xo ??
* @param yo ??
*/
private void drawDownArrow(final Graphics g, final int xo, final int yo) {
g.setColor(this.edge1);
g.drawLine(xo, yo, xo + this.size - 1, yo);
g.drawLine(xo, yo + 1, xo + this.size - 3, yo + 1);
g.setColor(this.edge2);
g.drawLine(xo + this.size - 2, yo + 1, xo + this.size - 1, yo + 1);
int x = xo + 1;
int y = yo + 2;
int dx = this.size - 6;
while (y + 1 < yo + this.size) {
g.setColor(this.edge1);
g.drawLine(x, y, x + 1, y);
g.drawLine(x, y + 1, x + 1, y + 1);
if (0 < dx) {
g.setColor(this.fill);
g.drawLine(x + 2, y, x + 1 + dx, y);
g.drawLine(x + 2, y + 1, x + 1 + dx, y + 1);
}
g.setColor(this.edge2);
g.drawLine(x + dx + 2, y, x + dx + 3, y);
g.drawLine(x + dx + 2, y + 1, x + dx + 3, y + 1);
x += 1;
y += 2;
dx -= 2;
}
g.setColor(this.edge1);
g.drawLine(
xo + (this.size / 2), yo + this.size - 1, xo + (this.size / 2), yo + this.size - 1
);
}
/**
* Draws the arrow pointing up.
*
* @param g the graphics device.
* @param xo ??
* @param yo ??
*/
private void drawUpArrow(final Graphics g, final int xo, final int yo) {
g.setColor(this.edge1);
int x = xo + (this.size / 2);
g.drawLine(x, yo, x, yo);
x--;
int y = yo + 1;
int dx = 0;
while (y + 3 < yo + this.size) {
g.setColor(this.edge1);
g.drawLine(x, y, x + 1, y);
g.drawLine(x, y + 1, x + 1, y + 1);
if (0 < dx) {
g.setColor(this.fill);
g.drawLine(x + 2, y, x + 1 + dx, y);
g.drawLine(x + 2, y + 1, x + 1 + dx, y + 1);
}
g.setColor(this.edge2);
g.drawLine(x + dx + 2, y, x + dx + 3, y);
g.drawLine(x + dx + 2, y + 1, x + dx + 3, y + 1);
x -= 1;
y += 2;
dx += 2;
}
g.setColor(this.edge1);
g.drawLine(xo, yo + this.size - 3, xo + 1, yo + this.size - 3);
g.setColor(this.edge2);
g.drawLine(xo + 2, yo + this.size - 2, xo + this.size - 1, yo + this.size - 2);
g.drawLine(xo, yo + this.size - 1, xo + this.size, yo + this.size - 1);
}
}
Bean Property Table Model
/*
* Copyright (C) 2001-2003 Colin Bell
* colbell@users.sourceforge.net
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.ruparator;
import java.util.Vector;
import javax.swing.table.DefaultTableModel;
public class BeanPropertyTableModel extends DefaultTableModel
{
private static final long serialVersionUID = 1L;
private Object _bean;
private String _nameColumnName = "Namecolumn";
private String _valueColumnName = "Valuecolumn";
public BeanPropertyTableModel()
{
super();
}
public void setBean(Object bean) throws RuntimeException
{
_bean = bean;
refresh();
}
public void refresh() throws RuntimeException
{
final Vector<Object> columnNames = new Vector<Object>();
columnNames.add(_nameColumnName);
columnNames.add(_valueColumnName);
final Vector<Object> columnData = new Vector<Object>();
if (_bean != null)
{
try
{
BeanInfo info = Introspector.getBeanInfo(_bean.getClass(), Introspector.USE_ALL_BEANINFO);
processBeanInfo(info, columnData);
}
catch (Exception ex)
{
throw new RuntimeException(ex);
}
}
// Sort the rows by the property name.
Collections.sort(columnData, new DataSorter());
setDataVector(columnData, columnNames);
}
private void processBeanInfo(BeanInfo info, Vector<Object> columnData)
throws InvocationTargetException, IllegalAccessException
{
BeanInfo[] extra = info.getAdditionalBeanInfo();
if (extra != null)
{
for (int i = 0; i < extra.length; ++i)
{
processBeanInfo(extra[i], columnData);
}
}
PropertyDescriptor[] propDesc = info.getPropertyDescriptors();
for (int i = 0; i < propDesc.length; ++i)
{
final String propName = propDesc[i].getName();
final Method getter = propDesc[i].getReadMethod();
if (propName != null && getter != null)
{
Vector<Object> line = generateLine(propName, _bean, getter);
if (line != null)
{
columnData.add(line);
}
}
}
}
/**
* Generate a line for the passed property.
*
* @param propName Name of the property.
* @param bean Bean containg the property.
* @param getter The "getter" function to retrieve the
* properties value.
*
* @return A <CODE>Vector</CODE> containing the cells for the line in
* the table. Element zero the first cell etc. Return
* <CODE>null</CODE> if this property is <B>not</B> to be added
* to the table.
*/
protected Vector<Object> generateLine(String propName, Object bean, Method getter)
throws InvocationTargetException, IllegalAccessException
{
final Vector<Object> line = new Vector<Object>();
line.add(propName);
line.add(executeGetter(bean, getter));
return line;
}
protected Object executeGetter(Object bean, Method getter)
throws InvocationTargetException, IllegalAccessException
{
return getter.invoke(bean, (Object[])null);
}
public void setNameColumnName(String value)
{
_nameColumnName = value;
}
public void setValueColumnName(String value)
{
_valueColumnName = value;
}
/**
* This comparator is compatible with the strange use of lists in this
* class. This classes lists are Vectors with Strings as the first element
* and any object as the other objects.
*/
private static final class DataSorter implements Comparator<Object>
{
public int compare(Object o1, Object o2)
{
Vector<Object> v1 = (Vector<Object>)o1;
Vector<Object> v2 = (Vector<Object>)o2;
String lhs = (String)v1.get(0);
String rhs = (String)v2.get(0);
return lhs.rupareToIgnoreCase(rhs);
}
}
}
Converts a column index in the model to a visible column index
import javax.swing.JTable;
import javax.swing.table.TableColumn;
public class Main {
public static void main(String[] argv) throws Exception {
}
public int toView(JTable table, int mColIndex) {
for (int c = 0; c < table.getColumnCount(); c++) {
TableColumn col = table.getColumnModel().getColumn(c);
if (col.getModelIndex() == mColIndex) {
return c;
}
}
return -1;
}
}
Converts a visible column index to a column index in the model.
import javax.swing.JTable;
public class Main {
public static void main(String[] argv) {
}
public int toModel(JTable table, int vColIndex) {
if (vColIndex >= table.getColumnCount()) {
return -1;
}
return table.getColumnModel().getColumn(vColIndex).getModelIndex();
}
}
Copy (clone) the data from the second row
import java.util.ArrayList;
import java.util.Vector;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
public class Main {
public static void main(String[] argv) throws Exception {
DefaultTableModel model = new DefaultTableModel();
JTable table = new JTable(model);
model.addColumn("Col1");
model.addRow(new Object[] { "r1" });
model.addRow(new Object[] { "r2" });
model.addRow(new Object[] { "r3" });
// Get all the table data
Vector data = model.getDataVector();
// Copy the second row
Vector row = (Vector) data.elementAt(1);
row = (Vector) row.clone();
JFrame f = new JFrame();
f.setSize(300, 300);
f.add(new JScrollPane(table));
f.setVisible(true);
}
}
Copy data from a table to a list
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
public class Main {
public static void main(String[] argv) throws Exception {
DefaultTableModel model = new DefaultTableModel();
JTable table = new JTable(model);
model.addColumn("Col1");
model.addRow(new Object[] { "r1" });
model.addRow(new Object[] { "r2" });
model.addRow(new Object[] { "r3" });
Vector data = model.getDataVector();
Vector row = (Vector) data.elementAt(1);
// Copy the first column
int mColIndex = 0;
List colData = new ArrayList(table.getRowCount());
for (int i = 0; i < table.getRowCount(); i++) {
row = (Vector) data.elementAt(i);
colData.add(row.get(mColIndex));
}
JFrame f = new JFrame();
f.setSize(300, 300);
f.add(new JScrollPane(table));
f.setVisible(true);
}
}
Creating simple JTable using AbstractTableModel
import java.awt.Dimension;
import java.util.Vector;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
public class Main extends JFrame {
private JTable m_simpleTable;
private SimpleTableModel m_simpleTableModel;
public Main() {
Vector dummyMacData = new Vector(10, 10);
dummyMacData.addElement(new Data(new Integer(100), "A", "1","C", "E"));
dummyMacData.addElement(new Data(new Integer(105), "R", "2","S", "E"));
m_simpleTableModel = new SimpleTableModel(dummyMacData);
m_simpleTable = new JTable(m_simpleTableModel);
JScrollPane scrollPane = new JScrollPane(m_simpleTable);
getContentPane().add(scrollPane);
}
public static void main(String[] arg) {
Main m = new Main();
m.setVisible(true);
m.setSize(new Dimension(600, 300));
m.validate();
}
class SimpleTableModel extends AbstractTableModel {
public String[] m_colNames = { "A", "B", "C","D", "E" };
public Class[] m_colTypes = { Integer.class, String.class, String.class, String.class,
String.class };
Vector m_macDataVector;
public SimpleTableModel(Vector macDataVector) {
super();
m_macDataVector = macDataVector;
}
public int getColumnCount() {
return m_colNames.length;
}
public int getRowCount() {
return m_macDataVector.size();
}
public void setValueAt(Object value, int row, int col) {
Data macData = (Data) (m_macDataVector.elementAt(row));
switch (col) {
case 0:
macData.setA((Integer) value);
break;
case 1:
macData.setB((String) value);
break;
case 2:
macData.setC((String) value);
break;
case 3:
macData.setD((String) value);
break;
case 4:
macData.setE((String) value);
break;
}
}
public String getColumnName(int col) {
return m_colNames[col];
}
public Class getColumnClass(int col) {
return m_colTypes[col];
}
public Object getValueAt(int row, int col) {
Data macData = (Data) (m_macDataVector.elementAt(row));
switch (col) {
case 0:
return macData.getA();
case 1:
return macData.getB();
case 2:
return macData.getC();
case 3:
return macData.getD();
case 4:
return macData.getE();
}
return new String();
}
}
}
class Data {
private Integer a;
private String b;
private String c;
private String d;
private String e;
public Data() {
}
public Data(Integer aa, String bb, String cc, String dd, String ee) {
a = aa;
b = bb;
c = cc;
d = dd;
e = ee;
}
public Integer getA() {
return a;
}
public String getB() {
return b;
}
public String getC() {
return c;
}
public String getD() {
return d;
}
public String getE() {
return e;
}
public void setA(Integer aa) {
a = aa;
}
public void setB(String macName) {
b = macName;
}
public void setC(String cc) {
c = cc;
}
public void setD(String dd) {
d = dd;
}
public void setE(String ee) {
e = ee;
}
}
Custom model, POJO and JTable
/*
Java Swing, 2nd Edition
By Marc Loy, Robert Eckstein, Dave Wood, James Elliott, Brian Cole
ISBN: 0-596-00408-7
Publisher: O"Reilly
*/
// MarketTable.java
//An application that display stock market data in a JTable. The table
//uses the MarketDataModel class for its model. MYOSM should be running
//to make the data dynamic.
//
import java.awt.BorderLayout;
import java.util.Date;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
public class MarketTable extends JFrame {
public MarketTable() {
super("Dynamic Data Test");
setSize(300, 200);
setDefaultCloseOperation(EXIT_ON_CLOSE);
// Set up our table model with a 5-second polling delay
MarketDataModel mdm = new MarketDataModel(5);
// Pick which stocks we want to watch . . .
mdm.setStocks(new int[] { 0, 1, 2 });
// And pop up the table
JTable jt = new JTable(mdm);
JScrollPane jsp = new JScrollPane(jt);
getContentPane().add(jsp, BorderLayout.CENTER);
}
public static void main(String args[]) {
MarketTable mt = new MarketTable();
mt.setVisible(true);
}
}
//MarketDataModel.java
//A custom table model for use with the MYOSM enviornment.
//
class MarketDataModel extends AbstractTableModel implements Runnable {
Thread runner;
MYOSM market;
int delay;
public MarketDataModel(int initialDelay) {
market = new MYOSM();
delay = initialDelay * 1000;
Thread runner = new Thread(this);
runner.start();
}
Stock[] stocks = new Stock[0];
int[] stockIndices = new int[0];
String[] headers = { "Symbol", "Price", "Change", "Last updated" };
public int getRowCount() {
return stocks.length;
}
public int getColumnCount() {
return headers.length;
}
public String getColumnName(int c) {
return headers[c];
}
public Object getValueAt(int r, int c) {
switch (c) {
case 0:
return stocks[r].symbol;
case 1:
return new Double(stocks[r].price);
case 2:
return new Double(stocks[r].delta);
case 3:
return stocks[r].lastUpdate;
}
throw new IllegalArgumentException("Bad cell (" + r + ", " + c + ")");
}
public void setDelay(int seconds) {
delay = seconds * 1000;
}
public void setStocks(int[] indices) {
stockIndices = indices;
updateStocks();
fireTableDataChanged();
}
public void updateStocks() {
stocks = new Stock[stockIndices.length];
for (int i = 0; i < stocks.length; i++) {
stocks[i] = market.getQuote(stockIndices[i]);
}
}
public void run() {
while (true) {
// Blind update . . . we could check for real deltas if necessary
updateStocks();
// We know there are no new columns, so don"t fire a data change,
// only
// fire a row update . . . this keeps the table from flashing
fireTableRowsUpdated(0, stocks.length - 1);
try {
Thread.sleep(delay);
} catch (InterruptedException ie) {
}
}
}
}
//Stock.java
//A simple aggregate class for storing stock market information on a single
//stock (symbol, price, etc.).
//
class Stock {
String symbol;
double price;
double delta;
Date lastUpdate;
public Stock(String s, double p) {
symbol = s;
price = p;
lastUpdate = new Date();
}
public void update(double d) {
delta = d;
price += delta;
}
public void print() {
System.out.println(symbol + ": " + price + " (" + delta
+ ") last updated " + lastUpdate);
}
}
//MYOSM.java
//Make Your Own Stock Market: A simple stock market simulator that contains a
//few stocks and their current prices (and deltas). It randomly adjusts the
//prices on stocks to give a dynamic feel to the data.
//
class MYOSM extends JFrame implements Runnable {
Stock[] market = { new Stock("JTree", 14.57), new Stock("JTable", 17.44),
new Stock("JList", 16.44), new Stock("JButton", 7.21),
new Stock("JComponent", 27.40) };
boolean monitor;
Random rg = new Random();
Thread runner;
public MYOSM() {
// Not meant to be shown as a real frame
super("Thread only version . . .");
runner = new Thread(this);
runner.start();
}
// This version creates a real frame so that you can see how the typical
// stocks get updated. It"s not meant to be used with other programs,
// but rather as a debugging tool to make sure the market runs ok.
public MYOSM(boolean monitorOn) {
super("Stock Market Monitor");
setSize(400, 100);
setDefaultCloseOperation(EXIT_ON_CLOSE);
monitor = monitorOn;
getContentPane().add(
new JLabel("Trading is active. "
+ "Close this window to close the market."),
BorderLayout.CENTER);
runner = new Thread(this);
runner.start();
}
// Here"s the heart of our stock market. In an infinite loop, just pick a
// random stock and update its price. To make the program interesting, we"ll
// update a price every second.
public void run() {
while (true) {
int whichStock = Math.abs(rg.nextInt()) % market.length;
double delta = rg.nextDouble() - 0.4;
market[whichStock].update(delta);
if (monitor) {
market[whichStock].print();
}
try {
Thread.sleep(1000);
} catch (InterruptedException ie) {
}
}
}
public Stock getQuote(int index) {
return market[index];
}
// This method returns the list of all the symbols in the market table
public String[] getSymbols() {
String[] symbols = new String[market.length];
for (int i = 0; i < market.length; i++) {
symbols[i] = market[i].symbol;
}
return symbols;
}
public static void main(String args[]) {
MYOSM myMarket = new MYOSM(args.length > 0);
myMarket.setVisible(true);
}
}
Custom table model, File data based Model
/*
Java Swing, 2nd Edition
By Marc Loy, Robert Eckstein, Dave Wood, James Elliott, Brian Cole
ISBN: 0-596-00408-7
Publisher: O"Reilly
*/
// FileTable2.java
//A test frame for the custom table model, FileModel. This version uses a
//custom renderer (BigRenderer.java) to flag large files with an exclamation
//point icon.
import java.awt.BorderLayout;
import java.awt.ruponent;
import java.io.File;
import java.util.Date;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingConstants;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
public class FileTable2 extends JFrame {
public FileTable2() {
super("Custom TableModel Test");
setSize(300, 200);
setDefaultCloseOperation(EXIT_ON_CLOSE);
FileModel fm = new FileModel();
JTable jt = new JTable(fm);
jt.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
jt.setColumnSelectionAllowed(true);
jt.setDefaultRenderer(Number.class, new BigRenderer(1000));
JScrollPane jsp = new JScrollPane(jt);
getContentPane().add(jsp, BorderLayout.CENTER);
}
public static void main(String args[]) {
FileTable2 ft = new FileTable2();
ft.setVisible(true);
}
}
//FileModel.java
//A custom table model to display information on a directory of files.
//
class FileModel extends AbstractTableModel {
String titles[] = new String[] { "Directory?", "File Name", "Read?",
"Write?", "Size", "Last Modified" };
Class types[] = new Class[] { Boolean.class, String.class, Boolean.class,
Boolean.class, Number.class, Date.class };
Object data[][];
public FileModel() {
this(".");
}
public FileModel(String dir) {
File pwd = new File(dir);
setFileStats(pwd);
}
// Implement the methods of the TableModel interface we"re interested
// in. Only getRowCount(), getColumnCount() and getValueAt() are
// required. The other methods tailor the look of the table.
public int getRowCount() {
return data.length;
}
public int getColumnCount() {
return titles.length;
}
public String getColumnName(int c) {
return titles[c];
}
public Class getColumnClass(int c) {
return types[c];
}
public Object getValueAt(int r, int c) {
return data[r][c];
}
// Our own method for setting/changing the current directory
// being displayed. This method fills the data set with file info
// from the given directory. It also fires an update event so this
// method could also be called after the table is on display.
public void setFileStats(File dir) {
String files[] = dir.list();
data = new Object[files.length][titles.length];
for (int i = 0; i < files.length; i++) {
File tmp = new File(files[i]);
data[i][0] = new Boolean(tmp.isDirectory());
data[i][1] = tmp.getName();
data[i][2] = new Boolean(tmp.canRead());
data[i][3] = new Boolean(tmp.canWrite());
data[i][4] = new Long(tmp.length());
data[i][5] = new Date(tmp.lastModified());
}
// Just in case anyone"s listening...
fireTableDataChanged();
}
}
//BigRenderer.java
//A renderer for numbers that shows an icon in front of big numbers.
//
class BigRenderer extends DefaultTableCellRenderer {
double threshold;
Icon bang = new ImageIcon("bang.gif");
public BigRenderer(double t) {
threshold = t;
setHorizontalAlignment(JLabel.RIGHT);
setHorizontalTextPosition(SwingConstants.RIGHT);
}
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int col) {
// be a little paranoid about where the user tries to use this renderer
if (value instanceof Number) {
if (((Number) value).doubleValue() > threshold) {
setIcon(bang);
} else {
setIcon(null);
}
} else {
setIcon(null);
}
return super.getTableCellRendererComponent(table, value, isSelected,
hasFocus, row, col);
}
}
Disable autoCreateColumnsFromModel
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
public class Main {
public static void main(String[] argv) throws Exception {
DefaultTableModel model = new DefaultTableModel();
JTable table = new JTable(model);
// Disable autoCreateColumnsFromModel
table.setAutoCreateColumnsFromModel(false);
}
}
extends AbstractTableModel to create custom model
/*
Definitive Guide to Swing for Java 2, Second Edition
By John Zukowski
ISBN: 1-893115-78-X
Publisher: APress
*/
import java.util.Date;
import javax.swing.*;
import javax.swing.table.*;
import java.awt.*;
public class ColumnSample {
public static void main(String args[]) {
TableModel model = new AbstractTableModel() {
Icon icon1 = new ImageIcon("TreeCollapsed.gif");
Icon icon2 = new ImageIcon("TreeExpanded.gif");
Object rowData[][] = {
{ "1", "ichi", Boolean.TRUE, new Date("01/01/2000"), icon1 },
{ "2", "ni", Boolean.TRUE, new Date("04/15/1999"), icon2 },
{ "3", "san", Boolean.FALSE, new Date("12/07/1941"), icon2 },
{ "4", "shi", Boolean.TRUE, new Date("02/29/2000"), icon1 },
{ "5", "go", Boolean.FALSE, new Date("05/23/1995"), icon1 }, };
String columnNames[] = { "English", "Japanese", "Boolean", "Date",
"ImageIcon" };
public int getColumnCount() {
return columnNames.length;
}
public String getColumnName(int column) {
return columnNames[column];
}
public int getRowCount() {
return rowData.length;
}
public Object getValueAt(int row, int column) {
return rowData[row][column];
}
public Class getColumnClass(int column) {
return (getValueAt(0, column).getClass());
}
};
JFrame frame = new JFrame("Column Renderer Table");
JTable table = new JTable(model);
JScrollPane scrollPane = new JScrollPane(table);
frame.getContentPane().add(scrollPane, BorderLayout.CENTER);
frame.setSize(400, 150);
frame.setVisible(true);
}
}
extends DefaultTableModel to create your own table model and build table from that
import java.awt.BorderLayout;
import java.util.Vector;
import javax.swing.DefaultCellEditor;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;
public class TableSample2 {
public static void main(String args[]) {
Object rows[][] = { { "one", "ichi - \u4E00", "un" },
{ "two", "ni - \u4E8C", "deux" },
{ "three", "san - \u4E09", "trois" },
{ "four", "shi - \u56DB", "quatre" },
{ "five", "go - \u4E94", "cinq" },
{ "six", "roku - \u516D", "treiza" },
{ "seven", "shichi - \u4E03", "sept" },
{ "eight", "hachi - \u516B", "huit" },
{ "nine", "kyu - \u4E5D", "neuf" },
{ "ten", "ju - \u5341", "dix" }
};
Object options[] = { "un", "deux", "trois", "quatre", "cinq", "treiza",
"sept", "huit", "neuf", "dix" };
JComboBox comboBox = new JComboBox(options);
comboBox.setMaximumRowCount(4);
TableCellEditor editor = new DefaultCellEditor(comboBox);
Object headers[] = { "English", "Japanese", "French" };
JFrame frame = new JFrame("JTable Anatomy");
class CustomTableModel extends DefaultTableModel {
public CustomTableModel(Object rowData[][], Object columnNames[]) {
super(rowData, columnNames);
}
public Class getColumnClass(int col) {
Vector v = (Vector) dataVector.elementAt(0);
return v.elementAt(col).getClass();
}
public boolean isCellEditable(int row, int col) {
return true;
}
}
JTable table = new JTable(new DefaultTableModel(rows, headers));
// ColumnModelUtilities.removeHeaders(table.getColumnModel());
table.getColumnModel().getColumn(2).setCellEditor(editor);
JScrollPane scrollPane = new JScrollPane(table);
frame.getContentPane().add(scrollPane, BorderLayout.CENTER);
frame.setSize(300, 150);
frame.setVisible(true);
}
}
File data Table: file name, size, type
/*
* This example is from the book "Java Foundation Classes in a Nutshell".
* Written by David Flanagan. Copyright (c) 1999 by O"Reilly & Associates.
* You may distribute this source code for non-commercial purposes only.
* You may study, modify, and use this example for any purpose, as long as
* this notice is retained. Note that this example is provided "as is",
* WITHOUT WARRANTY of any kind either expressed or implied.
*/
import javax.swing.*;
import javax.swing.table.*;
import java.io.File;
import java.util.Date;
public class FileTableDemo {
public static void main(String[] args) {
// Figure out what directory to display;
File dir;
if (args.length > 0) dir = new File(args[0]);
else dir = new File(System.getProperty("user.home"));
// Create a TableModel object to represent the contents of the directory
FileTableModel model = new FileTableModel(dir);
// Create a JTable and tell it to display our model
JTable table = new JTable(model);
// Display it all in a scrolling window and make the window appear
JFrame frame = new JFrame("FileTableDemo");
frame.getContentPane().add(new JScrollPane(table), "Center");
frame.setSize(600, 400);
frame.setVisible(true);
}
}
/**
* The methods in this class allow the JTable component to get
* and display data about the files in a specified directly.
* It represents a table with 6 columns: file name, size, modification date,
* plus three columns for flags: directory, readable, writable
**/
class FileTableModel extends AbstractTableModel {
protected File dir;
protected String[] filenames;
protected String[] columnNames = new String[] {
"name", "size", "last modified", "directory?", "readable?", "writable?"
};
protected Class[] columnClasses = new Class[] {
String.class, Long.class, Date.class,
Boolean.class, Boolean.class, Boolean.class
};
// This table model works for any one given directory
public FileTableModel(File dir) {
this.dir = dir;
this.filenames = dir.list(); // Store a list of files in the directory
}
// These are easy methods.
public int getColumnCount() { return 6; } // A constant for this model
public int getRowCount() { return filenames.length; } // # of files in dir
// Information about each column.
public String getColumnName(int col) { return columnNames[col]; }
public Class getColumnClass(int col) { return columnClasses[col]; }
// The method that must actually return the value of each cell.
public Object getValueAt(int row, int col) {
File f = new File(dir, filenames[row]);
switch(col) {
case 0: return filenames[row];
case 1: return new Long(f.length());
case 2: return new Date(f.lastModified());
case 3: return f.isDirectory() ? Boolean.TRUE : Boolean.FALSE;
case 4: return f.canRead() ? Boolean.TRUE : Boolean.FALSE;
case 5: return f.canWrite() ? Boolean.TRUE : Boolean.FALSE;
default: return null;
}
}
}
Fixed data vs dynamic data Table
import java.awt.BorderLayout;
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JViewport;
import javax.swing.ListSelectionModel;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableModel;
public class FixedTable {
public static void main(String args[]) {
final Object rowData[][] = {
{ "1", "one", "ichi", "un", "I", "\u4E00" },
{ "2", "two", "ni", "deux", "II", "\u4E8C" },
{ "3", "three", "san", "trois", "III", "\u4E09" },
{ "4", "four", "shi", "quatre", "IV", "\u56DB" },
{ "5", "five", "go", "cinq", "V", "\u4E94" },
{ "6", "six", "roku", "treiza", "VI", "\u516D" },
{ "7", "seven", "shichi", "sept", "VII", "\u4E03" },
{ "8", "eight", "hachi", "huit", "VIII", "\u516B" },
{ "9", "nine", "kyu", "neur", "IX", "\u4E5D" },
{ "10", "ten", "ju", "dix", "X", "\u5341" } };
final String columnNames[] = { "#", "English", "Japanese", "French",
"Roman", "Kanji" };
TableModel fixedColumnModel = new AbstractTableModel() {
public int getColumnCount() {
return 1;
}
public String getColumnName(int column) {
return columnNames[column];
}
public int getRowCount() {
return rowData.length;
}
public Object getValueAt(int row, int column) {
return rowData[row][column];
}
};
TableModel mainModel = new AbstractTableModel() {
public int getColumnCount() {
return columnNames.length - 1;
}
public String getColumnName(int column) {
return columnNames[column + 1];
}
public int getRowCount() {
return rowData.length;
}
public Object getValueAt(int row, int column) {
return rowData[row][column + 1];
}
};
JTable fixedTable = new JTable(fixedColumnModel);
fixedTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
// fixedTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
JTable mainTable = new JTable(mainModel);
mainTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
// mainTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
ListSelectionModel model = fixedTable.getSelectionModel();
mainTable.setSelectionModel(model);
JScrollPane scrollPane = new JScrollPane(mainTable);
Dimension fixedSize = fixedTable.getPreferredSize();
JViewport viewport = new JViewport();
viewport.setView(fixedTable);
viewport.setPreferredSize(fixedSize);
viewport.setMaximumSize(fixedSize);
scrollPane.setCorner(JScrollPane.UPPER_LEFT_CORNER, fixedTable
.getTableHeader());
scrollPane.setRowHeaderView(viewport);
JFrame frame = new JFrame("Fixed Column Table");
frame.getContentPane().add(scrollPane, BorderLayout.CENTER);
frame.setSize(300, 150);
frame.setVisible(true);
}
}
Get all the table data from DefaultTableModel
import java.util.ArrayList;
import java.util.Vector;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
public class Main {
public static void main(String[] argv) throws Exception {
DefaultTableModel model = new DefaultTableModel();
JTable table = new JTable(model);
model.addColumn("Col1");
model.addRow(new Object[] { "r1" });
model.addRow(new Object[] { "r2" });
model.addRow(new Object[] { "r3" });
// Get all the table data
Vector data = model.getDataVector();
JFrame f = new JFrame();
f.setSize(300, 300);
f.add(new JScrollPane(table));
f.setVisible(true);
}
}
Hard code data in array for TableModel
import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableModel;
public class AbstractSample {
public static void main(String args[]) {
TableModel model = new AbstractTableModel() {
Object rowData[][] = { { "one", "ichi" }, { "two", "ni" },
{ "three", "san" }, { "four", "shi" }, { "five", "go" },
{ "six", "roku" }, { "seven", "shichi" },
{ "eight", "hachi" }, { "nine", "kyu" }, { "ten", "ju" } };
Object columnNames[] = { "English", "Japanese" };
public String getColumnName(int column) {
return columnNames[column].toString();
}
public int getRowCount() {
return rowData.length;
}
public int getColumnCount() {
return columnNames.length;
}
public Object getValueAt(int row, int col) {
return rowData[row][col];
}
};
JFrame frame = new JFrame("Abstract Sample");
JTable table = new JTable(model);
JScrollPane scrollPane = new JScrollPane(table);
frame.getContentPane().add(scrollPane, BorderLayout.CENTER);
frame.setSize(300, 150);
frame.setVisible(true);
}
}
Insert a new column to a table
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
public class Main {
public static void main(String[] argv) throws Exception {
DefaultTableModel model = new DefaultTableModel();
JTable table = new JTable(model);
model.addColumn("Col1");
model.addRow(new Object[] { "r1" });
model.addRow(new Object[] { "r2" });
model.addRow(new Object[] { "r3" });
Vector data = model.getDataVector();
Vector row = (Vector) data.elementAt(1);
int mColIndex = 0;
List colData = new ArrayList(table.getRowCount());
for (int i = 0; i < table.getRowCount(); i++) {
row = (Vector) data.elementAt(i);
colData.add(row.get(mColIndex));
}
// Append a new column with copied data
model.addColumn("Col3", colData.toArray());
JFrame f = new JFrame();
f.setSize(300, 300);
f.add(new JScrollPane(table));
f.setVisible(true);
}
}
JTable class using default table models and a convenience
/*
Java Swing, 2nd Edition
By Marc Loy, Robert Eckstein, Dave Wood, James Elliott, Brian Cole
ISBN: 0-596-00408-7
Publisher: O"Reilly
*/
// SimpleTable.java
//A test of the JTable class using default table models and a convenience
//constructor.
//
import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
public class SimpleTable extends JFrame {
public SimpleTable() {
super("Simple JTable Test");
setSize(300, 200);
setDefaultCloseOperation(EXIT_ON_CLOSE);
JTable jt = new JTable(new String[][] { { "This", "is" },
{ "a", "Test" } }, new String[] { "Column", "Header" });
JScrollPane jsp = new JScrollPane(jt);
getContentPane().add(jsp, BorderLayout.CENTER);
}
public static void main(String args[]) {
SimpleTable st = new SimpleTable();
st.setVisible(true);
}
}
Map TableModel
/*
* Project: Gulden Utilies
* Class: de.gulden.util.swing.MapTableModel
* Version: snapshot-beautyj-1.1
*
* Date: 2004-09-29
*
* This is a snapshot version of the Gulden Utilities,
* it is not released as a seperate version.
*
* Note: Contains auto-generated Javadoc comments created by BeautyJ.
*
* This is licensed under the GNU Lesser General Public License (LGPL)
* and comes with NO WARRANTY.
*
* Author: Jens Gulden
* Email: amoda@jensgulden.de
*/
import java.util.*;
import java.util.Map;
import javax.swing.table.AbstractTableModel;
/**
* Class MapTableModel.
*
* @author Jens Gulden
* @version snapshot-beautyj-1.1
*/
public class MapTableModel extends AbstractTableModel {
// ------------------------------------------------------------------------
// --- fields ---
// ------------------------------------------------------------------------
/**
* The map.
*/
protected Map map;
/**
* The column names array.
*/
protected String[] columnNames;
// ------------------------------------------------------------------------
// --- constructors ---
// ------------------------------------------------------------------------
/**
* Creates a new instance of MapTableModel.
*/
public MapTableModel() {
super();
}
/**
* Creates a new instance of MapTableModel.
*/
public MapTableModel(Map map) {
this(map,"Entry","Value");
}
/**
* Creates a new instance of MapTableModel.
*/
public MapTableModel(Map map, String keyName, String valueName) {
this();
setMap(map);
setColumnNames(keyName,valueName);
}
// ------------------------------------------------------------------------
// --- methods ---
// ------------------------------------------------------------------------
/**
* Returns the row count.
*/
public int getRowCount() {
return map.size();
}
/**
* Returns the column count.
*/
public int getColumnCount() {
return 2;
}
/**
* Returns the value at.
*/
public Object getValueAt(int row, int column) {
Object[] entries=map.entrySet().toArray();
Map.Entry entry=(Map.Entry)entries[row];
if (column==0) {
return entry.getKey();
} else if (column==1) { // column==1
return entry.getValue();
} else {
throw new IndexOutOfBoundsException("MapTableModel provides a 2-column table, column-index "+column+" is illegal.");
}
}
/**
* Returns the column name.
*/
public String getColumnName(int column) {
return columnNames[column];
}
/**
* Sets the column names.
*/
public void setColumnNames(String keyName, String valueName) {
String[] names={keyName,valueName};
columnNames=names;
}
/**
* Returns the map.
*/
public Map getMap() {
return map;
}
/**
* Sets the map.
*/
public void setMap(Map _map) {
map = _map;
}
} // end MapTableModel
Move the first row to the end of the table
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
public class Main {
public static void main(String[] argv) throws Exception {
DefaultTableModel model = new DefaultTableModel();
JTable table = new JTable(model);
model.addColumn("Col1");
model.addRow(new Object[] { "r1" });
model.addRow(new Object[] { "r2" });
model.addRow(new Object[] { "r3" });
// Move the first row to the end of the table
model.moveRow(0, 0, model.getRowCount() - 1);
JFrame f = new JFrame();
f.setSize(300, 300);
f.add(new JScrollPane(table));
f.setVisible(true);
}
}
Move the first two rows to the end of the table
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
public class Main {
public static void main(String[] argv) throws Exception {
DefaultTableModel model = new DefaultTableModel();
JTable table = new JTable(model);
model.addColumn("Col1");
model.addRow(new Object[] { "r1" });
model.addRow(new Object[] { "r2" });
model.addRow(new Object[] { "r3" });
// Move the first two rows to the end of the table
model.moveRow(0, 1, model.getRowCount() - 2);
JFrame f = new JFrame();
f.setSize(300, 300);
f.add(new JScrollPane(table));
f.setVisible(true);
}
}
Move the last row to the beginning of the table
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
public class Main {
public static void main(String[] argv) throws Exception {
DefaultTableModel model = new DefaultTableModel();
JTable table = new JTable(model);
model.addColumn("Col1");
model.addRow(new Object[] { "r1" });
model.addRow(new Object[] { "r2" });
model.addRow(new Object[] { "r3" });
// Move the last row to the beginning of the table
model.moveRow(model.getRowCount() - 1, model.getRowCount() - 1, 0);
JFrame f = new JFrame();
f.setSize(300, 300);
f.add(new JScrollPane(table));
f.setVisible(true);
}
}
Move the last two rows to the start of the table
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
public class Main {
public static void main(String[] argv) throws Exception {
DefaultTableModel model = new DefaultTableModel();
JTable table = new JTable(model);
model.addColumn("Col1");
model.addRow(new Object[] { "r1" });
model.addRow(new Object[] { "r2" });
model.addRow(new Object[] { "r3" });
// Move the last two rows to the start of the table
model.moveRow(model.getRowCount() - 2, model.getRowCount() - 1, 0);
JFrame f = new JFrame();
f.setSize(300, 300);
f.add(new JScrollPane(table));
f.setVisible(true);
}
}
Overwrite the date from the first row with DefaultTableModel
import java.util.ArrayList;
import java.util.Vector;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
public class Main {
public static void main(String[] argv) throws Exception {
DefaultTableModel model = new DefaultTableModel();
JTable table = new JTable(model);
model.addColumn("Col1");
model.addRow(new Object[] { "r1" });
model.addRow(new Object[] { "r2" });
model.addRow(new Object[] { "r3" });
Vector data = model.getDataVector();
Vector row = (Vector) data.elementAt(1);
// Overwrite the first row with the copy
Vector firstRow = (Vector) data.elementAt(0);
for (int i = 0; i < row.size(); i++) {
firstRow.set(i, row.get(i));
}
JFrame f = new JFrame();
f.setSize(300, 300);
f.add(new JScrollPane(table));
f.setVisible(true);
}
}
Paging JTable(Table) Model with an input field for dynamically altering the size of a page.
/*
Java Swing, 2nd Edition
By Marc Loy, Robert Eckstein, Dave Wood, James Elliott, Brian Cole
ISBN: 0-596-00408-7
Publisher: O"Reilly
*/
// PagingTester2.java
//A quick application that demonstrates the PagingModel. This version has
//an input field for dynamically altering the size of a page.
//
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.ruponent;
import java.awt.Graphics;
import java.awt.Polygon;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.ScrollPaneConstants;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableModel;
public class PagingTester2 extends JFrame {
public PagingTester2() {
super("Paged JTable Test");
setSize(300, 200);
setDefaultCloseOperation(EXIT_ON_CLOSE);
final PagingModel pm = new PagingModel();
final JTable jt = new JTable(pm);
// Use our own custom scrollpane.
JScrollPane jsp = PagingModel.createPagingScrollPaneForTable(jt);
getContentPane().add(jsp, BorderLayout.CENTER);
// Property features testing
JPanel p = new JPanel();
p.add(new JLabel("Page Size: "));
final JTextField tf = new JTextField("100", 6);
p.add(tf);
tf.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
pm.setPageSize(Integer.parseInt(tf.getText()));
}
});
getContentPane().add(p, BorderLayout.SOUTH);
}
public static void main(String args[]) {
PagingTester2 pt = new PagingTester2();
pt.setVisible(true);
}
}
//PagingModel.java
//A larger table model that performs "paging" of its data. This model
//reports a small number of rows (like 100 or so) as a "page" of data. You
//can switch pages to view all of the rows as needed using the pageDown()
//and pageUp() methods. Presumably, access to the other pages of data is
//dictated by other GUI elements such as up/down buttons, or maybe a text
//field that allows you to enter the page number you want to display.
//
class PagingModel extends AbstractTableModel {
protected int pageSize;
protected int pageOffset;
protected Record[] data;
public PagingModel() {
this(10000, 100);
}
public PagingModel(int numRows, int size) {
data = new Record[numRows];
pageSize = size;
// Fill our table with random data (from the Record() constructor).
for (int i = 0; i < data.length; i++) {
data[i] = new Record();
}
}
// Return values appropriate for the visible table part.
public int getRowCount() {
return Math.min(pageSize, data.length);
}
public int getColumnCount() {
return Record.getColumnCount();
}
// Work only on the visible part of the table.
public Object getValueAt(int row, int col) {
int realRow = row + (pageOffset * pageSize);
return data[realRow].getValueAt(col);
}
public String getColumnName(int col) {
return Record.getColumnName(col);
}
// Use this method to figure out which page you are on.
public int getPageOffset() {
return pageOffset;
}
public int getPageCount() {
return (int) Math.ceil((double) data.length / pageSize);
}
// Use this method if you want to know how big the real table is . . . we
// could also write "getRealValueAt()" if needed.
public int getRealRowCount() {
return data.length;
}
public int getPageSize() {
return pageSize;
}
public void setPageSize(int s) {
if (s == pageSize) {
return;
}
int oldPageSize = pageSize;
pageSize = s;
pageOffset = (oldPageSize * pageOffset) / pageSize;
fireTableDataChanged();
/*
* if (pageSize < oldPageSize) { fireTableRowsDeleted(pageSize,
* oldPageSize - 1); } else { fireTableRowsInserted(oldPageSize,
* pageSize - 1); }
*/
}
// Update the page offset and fire a data changed (all rows).
public void pageDown() {
if (pageOffset < getPageCount() - 1) {
pageOffset++;
fireTableDataChanged();
}
}
// Update the page offset and fire a data changed (all rows).
public void pageUp() {
if (pageOffset > 0) {
pageOffset--;
fireTableDataChanged();
}
}
// We provide our own version of a scrollpane that includes
// the page up and page down buttons by default.
public static JScrollPane createPagingScrollPaneForTable(JTable jt) {
JScrollPane jsp = new JScrollPane(jt);
TableModel tmodel = jt.getModel();
// Don"t choke if this is called on a regular table . . .
if (!(tmodel instanceof PagingModel)) {
return jsp;
}
// Okay, go ahead and build the real scrollpane
final PagingModel model = (PagingModel) tmodel;
final JButton upButton = new JButton(new ArrowIcon(ArrowIcon.UP));
upButton.setEnabled(false); // starts off at 0, so can"t go up
final JButton downButton = new JButton(new ArrowIcon(ArrowIcon.DOWN));
if (model.getPageCount() <= 1) {
downButton.setEnabled(false); // One page...can"t scroll down
}
upButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
model.pageUp();
// If we hit the top of the data, disable the up button.
if (model.getPageOffset() == 0) {
upButton.setEnabled(false);
}
downButton.setEnabled(true);
}
});
downButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
model.pageDown();
// If we hit the bottom of the data, disable the down button.
if (model.getPageOffset() == (model.getPageCount() - 1)) {
downButton.setEnabled(false);
}
upButton.setEnabled(true);
}
});
// Turn on the scrollbars; otherwise we won"t get our corners.
jsp
.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
jsp
.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
// Add in the corners (page up/down).
jsp.setCorner(ScrollPaneConstants.UPPER_RIGHT_CORNER, upButton);
jsp.setCorner(ScrollPaneConstants.LOWER_RIGHT_CORNER, downButton);
return jsp;
}
}
//Record.java
//A simple data structure for use with the PagingModel demo.
//
class Record {
static String[] headers = { "Record Number", "Batch Number", "Reserved" };
static int counter;
String[] data;
public Record() {
data = new String[] { "" + (counter++),
"" + System.currentTimeMillis(), "Reserved" };
}
public String getValueAt(int i) {
return data[i];
}
public static String getColumnName(int i) {
return headers[i];
}
public static int getColumnCount() {
return headers.length;
}
}
//ArrowIcon.java
//A simple implementation of the Icon interface that can make
//Up and Down arrows.
//
class ArrowIcon implements Icon {
public static final int UP = 0;
public static final int DOWN = 1;
private int direction;
private Polygon pagePolygon = new Polygon(new int[] { 2, 4, 4, 10, 10, 2 },
new int[] { 4, 4, 2, 2, 12, 12 }, 6);
private int[] arrowX = { 4, 9, 6 };
private Polygon arrowUpPolygon = new Polygon(arrowX,
new int[] { 10, 10, 4 }, 3);
private Polygon arrowDownPolygon = new Polygon(arrowX,
new int[] { 6, 6, 11 }, 3);
public ArrowIcon(int which) {
direction = which;
}
public int getIconWidth() {
return 14;
}
public int getIconHeight() {
return 14;
}
public void paintIcon(Component c, Graphics g, int x, int y) {
g.setColor(Color.black);
pagePolygon.translate(x, y);
g.drawPolygon(pagePolygon);
pagePolygon.translate(-x, -y);
if (direction == UP) {
arrowUpPolygon.translate(x, y);
g.fillPolygon(arrowUpPolygon);
arrowUpPolygon.translate(-x, -y);
} else {
arrowDownPolygon.translate(x, y);
g.fillPolygon(arrowDownPolygon);
arrowDownPolygon.translate(-x, -y);
}
}
}
Paging or pagable JTable(Table) Model for large data set
/*
Java Swing, 2nd Edition
By Marc Loy, Robert Eckstein, Dave Wood, James Elliott, Brian Cole
ISBN: 0-596-00408-7
Publisher: O"Reilly
*/
// PagingTester.java
//A quick application that demonstrates the PagingModel.
//
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.ruponent;
import java.awt.Graphics;
import java.awt.Polygon;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ScrollPaneConstants;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableModel;
public class PagingTester extends JFrame {
public PagingTester() {
super("Paged JTable Test");
setSize(300, 200);
setDefaultCloseOperation(EXIT_ON_CLOSE);
PagingModel pm = new PagingModel();
JTable jt = new JTable(pm);
// Use our own custom scrollpane.
JScrollPane jsp = PagingModel.createPagingScrollPaneForTable(jt);
getContentPane().add(jsp, BorderLayout.CENTER);
}
public static void main(String args[]) {
PagingTester pt = new PagingTester();
pt.setVisible(true);
}
}
//PagingModel.java
//A larger table model that performs "paging" of its data. This model
//reports a small number of rows (like 100 or so) as a "page" of data. You
//can switch pages to view all of the rows as needed using the pageDown()
//and pageUp() methods. Presumably, access to the other pages of data is
//dictated by other GUI elements such as up/down buttons, or maybe a text
//field that allows you to enter the page number you want to display.
//
class PagingModel extends AbstractTableModel {
protected int pageSize;
protected int pageOffset;
protected Record[] data;
public PagingModel() {
this(10000, 100);
}
public PagingModel(int numRows, int size) {
data = new Record[numRows];
pageSize = size;
// Fill our table with random data (from the Record() constructor).
for (int i = 0; i < data.length; i++) {
data[i] = new Record();
}
}
// Return values appropriate for the visible table part.
public int getRowCount() {
return Math.min(pageSize, data.length);
}
public int getColumnCount() {
return Record.getColumnCount();
}
// Work only on the visible part of the table.
public Object getValueAt(int row, int col) {
int realRow = row + (pageOffset * pageSize);
return data[realRow].getValueAt(col);
}
public String getColumnName(int col) {
return Record.getColumnName(col);
}
// Use this method to figure out which page you are on.
public int getPageOffset() {
return pageOffset;
}
public int getPageCount() {
return (int) Math.ceil((double) data.length / pageSize);
}
// Use this method if you want to know how big the real table is . . . we
// could also write "getRealValueAt()" if needed.
public int getRealRowCount() {
return data.length;
}
public int getPageSize() {
return pageSize;
}
public void setPageSize(int s) {
if (s == pageSize) {
return;
}
int oldPageSize = pageSize;
pageSize = s;
pageOffset = (oldPageSize * pageOffset) / pageSize;
fireTableDataChanged();
/*
* if (pageSize < oldPageSize) { fireTableRowsDeleted(pageSize,
* oldPageSize - 1); } else { fireTableRowsInserted(oldPageSize,
* pageSize - 1); }
*/
}
// Update the page offset and fire a data changed (all rows).
public void pageDown() {
if (pageOffset < getPageCount() - 1) {
pageOffset++;
fireTableDataChanged();
}
}
// Update the page offset and fire a data changed (all rows).
public void pageUp() {
if (pageOffset > 0) {
pageOffset--;
fireTableDataChanged();
}
}
// We provide our own version of a scrollpane that includes
// the page up and page down buttons by default.
public static JScrollPane createPagingScrollPaneForTable(JTable jt) {
JScrollPane jsp = new JScrollPane(jt);
TableModel tmodel = jt.getModel();
// Don"t choke if this is called on a regular table . . .
if (!(tmodel instanceof PagingModel)) {
return jsp;
}
// Okay, go ahead and build the real scrollpane
final PagingModel model = (PagingModel) tmodel;
final JButton upButton = new JButton(new ArrowIcon(ArrowIcon.UP));
upButton.setEnabled(false); // starts off at 0, so can"t go up
final JButton downButton = new JButton(new ArrowIcon(ArrowIcon.DOWN));
if (model.getPageCount() <= 1) {
downButton.setEnabled(false); // One page...can"t scroll down
}
upButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
model.pageUp();
// If we hit the top of the data, disable the up button.
if (model.getPageOffset() == 0) {
upButton.setEnabled(false);
}
downButton.setEnabled(true);
}
});
downButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
model.pageDown();
// If we hit the bottom of the data, disable the down button.
if (model.getPageOffset() == (model.getPageCount() - 1)) {
downButton.setEnabled(false);
}
upButton.setEnabled(true);
}
});
// Turn on the scrollbars; otherwise we won"t get our corners.
jsp
.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
jsp
.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
// Add in the corners (page up/down).
jsp.setCorner(ScrollPaneConstants.UPPER_RIGHT_CORNER, upButton);
jsp.setCorner(ScrollPaneConstants.LOWER_RIGHT_CORNER, downButton);
return jsp;
}
}
//Record.java
//A simple data structure for use with the PagingModel demo.
//
class Record {
static String[] headers = { "Record Number", "Batch Number", "Reserved" };
static int counter;
String[] data;
public Record() {
data = new String[] { "" + (counter++),
"" + System.currentTimeMillis(), "Reserved" };
}
public String getValueAt(int i) {
return data[i];
}
public static String getColumnName(int i) {
return headers[i];
}
public static int getColumnCount() {
return headers.length;
}
}
//ArrowIcon.java
//A simple implementation of the Icon interface that can make
//Up and Down arrows.
//
class ArrowIcon implements Icon {
public static final int UP = 0;
public static final int DOWN = 1;
private int direction;
private Polygon pagePolygon = new Polygon(new int[] { 2, 4, 4, 10, 10, 2 },
new int[] { 4, 4, 2, 2, 12, 12 }, 6);
private int[] arrowX = { 4, 9, 6 };
private Polygon arrowUpPolygon = new Polygon(arrowX,
new int[] { 10, 10, 4 }, 3);
private Polygon arrowDownPolygon = new Polygon(arrowX,
new int[] { 6, 6, 11 }, 3);
public ArrowIcon(int which) {
direction = which;
}
public int getIconWidth() {
return 14;
}
public int getIconHeight() {
return 14;
}
public void paintIcon(Component c, Graphics g, int x, int y) {
g.setColor(Color.black);
pagePolygon.translate(x, y);
g.drawPolygon(pagePolygon);
pagePolygon.translate(-x, -y);
if (direction == UP) {
arrowUpPolygon.translate(x, y);
g.fillPolygon(arrowUpPolygon);
arrowUpPolygon.translate(-x, -y);
} else {
arrowDownPolygon.translate(x, y);
g.fillPolygon(arrowDownPolygon);
arrowDownPolygon.translate(-x, -y);
}
}
}
Remove the first row from a table with DefaultTableModel
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
public class Main {
public static void main(String[] argv) throws Exception {
DefaultTableModel model = new DefaultTableModel();
JTable table = new JTable(model);
model.addColumn("Col1");
model.addRow(new Object[] { "r1" });
model.addRow(new Object[] { "r2" });
model.addRow(new Object[] { "r3" });
// Remove the first row
model.removeRow(0);
JFrame f = new JFrame();
f.setSize(300, 300);
f.add(new JScrollPane(table));
f.setVisible(true);
}
}
Remove the first visible column without removing the underlying data
import java.util.Enumeration;
import java.util.Vector;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
public class Main {
public static void main(String[] argv) throws Exception {
DefaultTableModel model = new MyDefaultTableModel();
JTable table = new JTable(model);
table.setModel(model);
model.addColumn("Col1");
model.addColumn("Col2");
model.addColumn("Col3");
model.addRow(new Object[] { "v1" });
table.removeColumn(table.getColumnModel().getColumn(0));
}
}
class MyDefaultTableModel extends DefaultTableModel {
public Vector getColumnIdentifiers() {
return columnIdentifiers;
}
}
Remove the last row from a table with DefaultTableModel
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
public class Main {
public static void main(String[] argv) throws Exception {
DefaultTableModel model = new DefaultTableModel();
JTable table = new JTable(model);
// Create some data
model.addColumn("Col1");
model.addRow(new Object[] { "r1" });
model.addRow(new Object[] { "r2" });
model.addRow(new Object[] { "r3" });
model.removeRow(model.getRowCount() - 1);
JFrame f = new JFrame();
f.setSize(300, 300);
f.add(new JScrollPane(table));
f.setVisible(true);
}
}
Returns the visible columns in the order that they appear in the model
import java.util.ArrayList;
import java.util.Collections;
import java.util.ruparator;
import java.util.Enumeration;
import java.util.List;
import javax.swing.JTable;
import javax.swing.table.TableColumn;
public class Main {
public static void main(String[] argv) {
}
//
public TableColumn[] getColumnsInModel(JTable table) {
List result = new ArrayList();
for (Enumeration e = table.getColumnModel().getColumns(); e.hasMoreElements();) {
result.add((TableColumn) e.nextElement());
}
Collections.sort(result, new TableColumnComparator());
return (TableColumn[]) result.toArray(new TableColumn[result.size()]);
}
}
class TableColumnComparator implements Comparator {
public int compare(Object a, Object b) {
TableColumn c1 = (TableColumn) a;
TableColumn c2 = (TableColumn) b;
if (c1.getModelIndex() < c2.getModelIndex()) {
return -1;
} else if (c1.getModelIndex() == c2.getModelIndex()) {
return 0;
} else {
return 1;
}
}
}
Sharing a Table Model Between JTable Components
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
public class Main {
public static void main(String[] argv) {
DefaultTableModel model = new DefaultTableModel();
JTable table1 = new JTable(model);
JTable table2 = new JTable(model);
JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
splitPane.add(new JScrollPane(table1));
splitPane.add(new JScrollPane(table2));
table1.getColumnModel().removeColumn(table1.getColumnModel().getColumn(0));
}
}
Stocks data Table: illustrate the TableModel
/*
Swing, Second Edition
by Matthew Robinson, Pavel Vorobiev
*/
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Vector;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingConstants;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableColumn;
public class StocksTable extends JFrame {
protected JTable m_table;
protected StockTableData m_data;
protected JLabel m_title;
public StocksTable() {
super("Stocks Table");
setSize(600, 300);
m_data = new StockTableData();
m_title = new JLabel(m_data.getTitle(), new ImageIcon("money.gif"),
SwingConstants.LEFT);
m_title.setFont(new Font("TimesRoman", Font.BOLD, 24));
m_title.setForeground(Color.black);
getContentPane().add(m_title, BorderLayout.NORTH);
m_table = new JTable();
m_table.setAutoCreateColumnsFromModel(false);
m_table.setModel(m_data);
for (int k = 0; k < StockTableData.m_columns.length; k++) {
DefaultTableCellRenderer renderer = new DefaultTableCellRenderer();
renderer
.setHorizontalAlignment(StockTableData.m_columns[k].m_alignment);
TableColumn column = new TableColumn(k,
StockTableData.m_columns[k].m_width, renderer, null);
m_table.addColumn(column);
}
JTableHeader header = m_table.getTableHeader();
header.setUpdateTableInRealTime(false);
JScrollPane ps = new JScrollPane();
ps.getViewport().add(m_table);
getContentPane().add(ps, BorderLayout.CENTER);
WindowListener wndCloser = new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
};
addWindowListener(wndCloser);
setVisible(true);
}
public static void main(String argv[]) {
new StocksTable();
}
}
class StockData {
public String m_symbol;
public String m_name;
public Double m_last;
public Double m_open;
public Double m_change;
public Double m_changePr;
public Long m_volume;
public StockData(String symbol, String name, double last, double open,
double change, double changePr, long volume) {
m_symbol = symbol;
m_name = name;
m_last = new Double(last);
m_open = new Double(open);
m_change = new Double(change);
m_changePr = new Double(changePr);
m_volume = new Long(volume);
}
}
class ColumnData {
public String m_title;
public int m_width;
public int m_alignment;
public ColumnData(String title, int width, int alignment) {
m_title = title;
m_width = width;
m_alignment = alignment;
}
}
class StockTableData extends AbstractTableModel {
static final public ColumnData m_columns[] = {
new ColumnData("Symbol", 100, JLabel.LEFT),
new ColumnData("Name", 160, JLabel.LEFT),
new ColumnData("Last", 100, JLabel.RIGHT),
new ColumnData("Open", 100, JLabel.RIGHT),
new ColumnData("Change", 100, JLabel.RIGHT),
new ColumnData("Change %", 100, JLabel.RIGHT),
new ColumnData("Volume", 100, JLabel.RIGHT) };
protected SimpleDateFormat m_frm;
protected Vector m_vector;
protected Date m_date;
public StockTableData() {
m_frm = new SimpleDateFormat("MM/dd/yyyy");
m_vector = new Vector();
setDefaultData();
}
public void setDefaultData() {
try {
m_date = m_frm.parse("4/6/1999");
} catch (java.text.ParseException ex) {
m_date = null;
}
m_vector.removeAllElements();
m_vector.addElement(new StockData("ORCL", "Oracle Corp.", 23.6875,
25.375, -1.6875, -6.42, 24976600));
m_vector.addElement(new StockData("EGGS", "Egghead.ru", 17.25,
17.4375, -0.1875, -1.43, 2146400));
m_vector.addElement(new StockData("T", "AT&T", 65.1875, 66, -0.8125,
-0.10, 554000));
m_vector.addElement(new StockData("LU", "Lucent Technology", 64.625,
59.9375, 4.6875, 9.65, 29856300));
m_vector.addElement(new StockData("FON", "Sprint", 104.5625, 106.375,
-1.8125, -1.82, 1135100));
m_vector.addElement(new StockData("ENML", "Enamelon Inc.", 4.875, 5,
-0.125, 0, 35900));
m_vector.addElement(new StockData("CPQ", "Compaq Computers", 30.875,
31.25, -0.375, -2.18, 11853900));
m_vector.addElement(new StockData("MSFT", "Microsoft Corp.", 94.0625,
95.1875, -1.125, -0.92, 19836900));
m_vector.addElement(new StockData("DELL", "Dell Computers", 46.1875,
44.5, 1.6875, 6.24, 47310000));
m_vector.addElement(new StockData("SUNW", "Sun Microsystems", 140.625,
130.9375, 10, 10.625, 17734600));
m_vector.addElement(new StockData("IBM", "Intl. Bus. Machines", 183,
183.125, -0.125, -0.51, 4371400));
m_vector.addElement(new StockData("HWP", "Hewlett-Packard", 70,
71.0625, -1.4375, -2.01, 2410700));
m_vector.addElement(new StockData("UIS", "Unisys Corp.", 28.25, 29,
-0.75, -2.59, 2576200));
m_vector.addElement(new StockData("SNE", "Sony Corp.", 96.1875, 95.625,
1.125, 1.18, 330600));
m_vector.addElement(new StockData("NOVL", "Novell Inc.", 24.0625,
24.375, -0.3125, -3.02, 6047900));
m_vector.addElement(new StockData("HIT", "Hitachi, Ltd.", 78.5, 77.625,
0.875, 1.12, 49400));
}
public int getRowCount() {
return m_vector == null ? 0 : m_vector.size();
}
public int getColumnCount() {
return m_columns.length;
}
public String getColumnName(int column) {
return m_columns[column].m_title;
}
public boolean isCellEditable(int nRow, int nCol) {
return false;
}
public Object getValueAt(int nRow, int nCol) {
if (nRow < 0 || nRow >= getRowCount())
return "";
StockData row = (StockData) m_vector.elementAt(nRow);
switch (nCol) {
case 0:
return row.m_symbol;
case 1:
return row.m_name;
case 2:
return row.m_last;
case 3:
return row.m_open;
case 4:
return row.m_change;
case 5:
return row.m_changePr;
case 6:
return row.m_volume;
}
return "";
}
public String getTitle() {
if (m_date == null)
return "Stock Quotes";
return "Stock Quotes at " + m_frm.format(m_date);
}
}
Table model is based on call back
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
public class ExampleTableModel extends AbstractTableModel {
String columnName[] = { "description", "data", "boolean values" };
Class columnType[] = { String.class, String.class, Boolean.class };
Object table[][] = { { "this is line", "data", new Boolean(true) },
{ "this is line", "data", new Boolean(false) },
{ "this is line", "data", new Boolean(true) },
{ "this is line", "data", new Boolean(false) },
{ "this is line", "data", new Boolean(true) },
{ "this is line", "data", new Boolean(false) },
{ "this is line", "data", new Boolean(true) },
{ "this is line", "data", new Boolean(false) },
{ "this is line", "data", new Boolean(true) } };
public int getColumnCount() {
return table[0].length;
}
public int getRowCount() {
return table.length;
}
public Object getValueAt(int r, int c) {
return table[r][c];
}
public String getColumnName(int column) {
return columnName[column];
}
public Class getColumnClass(int c) {
return columnType[c];
}
public boolean isCellEditable(int r, int c) {
return false;
}
public void setValueAt(Object aValue, int r, int c) {
}
public static void main(String[] arg){
JFrame f = new JFrame();
f.getContentPane().add(new JScrollPane(new JTable(new ExampleTableModel())));
f.setSize(300,300);
f.show();
}
}
TableSorter extends AbstractTableModel
/*
This file is part of BORG.
BORG is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
BORG is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with BORG; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Copyright 2003 by Mike Berger
*/
import java.awt.Color;
import java.awt.ruponent;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.ruparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.swing.Icon;
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.SwingConstants;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;
/**
* TableSorter is a decorator for TableModels; adding sorting
* functionality to a supplied TableModel. TableSorter does
* not store or copy the data in its TableModel; instead it maintains
* a map from the row indexes of the view to the row indexes of the
* model. As requests are made of the sorter (like getValueAt(row, col))
* they are passed to the underlying model after the row numbers
* have been translated via the internal mapping array. This way,
* the TableSorter appears to hold another copy of the table
* with the rows in a different order.
* <p/>
* TableSorter registers itself as a listener to the underlying model,
* just as the JTable itself would. Events recieved from the model
* are examined, sometimes manipulated (typically widened), and then
* passed on to the TableSorter"s listeners (typically the JTable).
* If a change to the model has invalidated the order of TableSorter"s
* rows, a note of this is made and the sorter will resort the
* rows the next time a value is requested.
* <p/>
* When the tableHeader property is set, either by using the
* setTableHeader() method or the two argument constructor, the
* table header may be used as a complete UI for TableSorter.
* The default renderer of the tableHeader is decorated with a renderer
* that indicates the sorting status of each column. In addition,
* a mouse listener is installed with the following behavior:
* <ul>
* <li>
* Mouse-click: Clears the sorting status of all other columns
* and advances the sorting status of that column through three
* values: {NOT_SORTED, ASCENDING, DESCENDING} (then back to
* NOT_SORTED again).
* <li>
* SHIFT-mouse-click: Clears the sorting status of all other columns
* and cycles the sorting status of the column through the same
* three values, in the opposite order: {NOT_SORTED, DESCENDING, ASCENDING}.
* <li>
* CONTROL-mouse-click and CONTROL-SHIFT-mouse-click: as above except
* that the changes to the column do not cancel the statuses of columns
* that are already sorting - giving a way to initiate a compound
* sort.
* </ul>
* <p/>
* This is a long overdue rewrite of a class of the same name that
* first appeared in the swing table demos in 1997.
*
* @author Philip Milne
* @author Brendon McLean
* @author Dan van Enckevort
* @author Parwinder Sekhon
* @version 2.0 02/27/04
*/
/* updated by Mike Berger
*
* - lots didn"t work out of the box. Plus code was added to make this object
* compatible with the old TableSorter so the rest of the code did not have to change
*/
@SuppressWarnings("unchecked") //$NON-NLS-1$
public class TableSorter extends AbstractTableModel {
protected TableModel tableModel;
public static final int DESCENDING = -1;
public static final int NOT_SORTED = 0;
public static final int ASCENDING = 1;
private static Directive EMPTY_DIRECTIVE = new Directive(-1, NOT_SORTED);
public static final Comparator<Object> COMPARABLE_COMAPRATOR = new Comparator() {
public int compare(Object o1, Object o2) {
return ((Comparable<Object>) o1).rupareTo(o2);
}
};
public static final Comparator<Object> LEXICAL_COMPARATOR = new Comparator() {
public int compare(Object o1, Object o2) {
return o1.toString().rupareTo(o2.toString());
}
};
private Row[] viewToModel;
private int[] modelToView;
private JTableHeader tableHeader;
private Map<Class, Comparator> columnComparators = new HashMap<Class, Comparator>();
private List<Directive> sortingColumns = new ArrayList<Directive>();
public TableSorter() {
}
private void clearSortingState() {
viewToModel = null;
modelToView = null;
}
public TableModel getTableModel() {
return tableModel;
}
public void setTableModel(TableModel tableModel) {
if (this.tableModel != null) {
this.tableModel.removeTableModelListener(tableModelListener);
}
this.tableModel = tableModel;
if (this.tableModel != null) {
this.tableModel.addTableModelListener(tableModelListener);
}
clearSortingState();
fireTableStructureChanged();
}
public JTableHeader getTableHeader() {
return tableHeader;
}
public void setTableHeader(JTableHeader tableHeader) {
if (this.tableHeader != null) {
this.tableHeader.removeMouseListener(mouseListener_);
TableCellRenderer defaultRenderer = this.tableHeader.getDefaultRenderer();
if (defaultRenderer instanceof SortableHeaderRenderer) {
this.tableHeader.setDefaultRenderer(((SortableHeaderRenderer) defaultRenderer).tableCellRenderer);
}
}
this.tableHeader = tableHeader;
if (this.tableHeader != null) {
this.tableHeader.addMouseListener(mouseListener_);
this.tableHeader.setDefaultRenderer(
new SortableHeaderRenderer(this.tableHeader.getDefaultRenderer()));
}
}
public boolean isSorting() {
return sortingColumns.size() != 0;
}
private Directive getDirective(int column) {
for (int i = 0; i < sortingColumns.size(); i++) {
Directive directive = sortingColumns.get(i);
if (directive.column == column) {
return directive;
}
}
return EMPTY_DIRECTIVE;
}
public int getSortingStatus(int column) {
return getDirective(column).direction;
}
private void sortingStatusChanged() {
clearSortingState();
fireTableDataChanged();
if (tableHeader != null) {
tableHeader.repaint();
}
}
public void setSortingStatus(int column, int status) {
Directive directive = getDirective(column);
if (directive != EMPTY_DIRECTIVE) {
sortingColumns.remove(directive);
}
if (status != NOT_SORTED) {
sortingColumns.add(new Directive(column, status));
}
sortingStatusChanged();
}
protected Icon getHeaderRendererIcon(int column, int size) {
Directive directive = getDirective(column);
if (directive == EMPTY_DIRECTIVE) {
return null;
}
return new Arrow(directive.direction == DESCENDING, size, sortingColumns.indexOf(directive));
}
private void cancelSorting() {
sortingColumns.clear();
sortingStatusChanged();
}
/* TODO UCdetector: Remove unused code:
public void setColumnComparator(Class type, Comparator comparator) {
if (comparator == null) {
columnComparators.remove(type);
} else {
columnComparators.put(type, comparator);
}
}
*/
protected Comparator<Object> getComparator(int column) {
Class columnType = tableModel.getColumnClass(column);
Comparator<Object> comparator = columnComparators.get(columnType);
if (comparator != null) {
return comparator;
}
if (Comparable.class.isAssignableFrom(columnType)) {
return COMPARABLE_COMAPRATOR;
}
return LEXICAL_COMPARATOR;
}
private Row[] getViewToModel() {
if (viewToModel == null) {
int tableModelRowCount = tableModel.getRowCount();
viewToModel = new Row[tableModelRowCount];
for (int row = 0; row < tableModelRowCount; row++) {
viewToModel[row] = new Row(row);
}
if (isSorting()) {
Arrays.sort(viewToModel);
}
}
return viewToModel;
}
public int modelIndex(int viewIndex) {
return getViewToModel()[viewIndex].modelIndex;
}
private int[] getModelToView() {
if (modelToView == null) {
int n = getViewToModel().length;
modelToView = new int[n];
for (int i = 0; i < n; i++) {
modelToView[modelIndex(i)] = i;
}
}
return modelToView;
}
// TableModel interface methods
public int getRowCount() {
return (tableModel == null) ? 0 : tableModel.getRowCount();
}
public int getColumnCount() {
return (tableModel == null) ? 0 : tableModel.getColumnCount();
}
public String getColumnName(int column) {
return tableModel.getColumnName(column);
}
public Class getColumnClass(int column) {
return tableModel.getColumnClass(column);
}
public boolean isCellEditable(int row, int column) {
return tableModel.isCellEditable(modelIndex(row), column);
}
public Object getValueAt(int row, int column) {
return tableModel.getValueAt(modelIndex(row), column);
}
public void setValueAt(Object aValue, int row, int column) {
tableModel.setValueAt(aValue, modelIndex(row), column);
}
// Helper classes
private class Row implements Comparable {
private int modelIndex;
public Row(int index) {
this.modelIndex = index;
}
public int compareTo(Object o) {
int row1 = modelIndex;
int row2 = ((Row) o).modelIndex;
for (Iterator<Directive> it = sortingColumns.iterator(); it.hasNext();) {
Directive directive = it.next();
int column = directive.column;
Object o1 = tableModel.getValueAt(row1, column);
Object o2 = tableModel.getValueAt(row2, column);
int comparison = 0;
// Define null less than everything, except null.
if (o1 == null && o2 == null) {
comparison = 0;
} else if (o1 == null) {
comparison = -1;
} else if (o2 == null) {
comparison = 1;
} else {
comparison = getComparator(column).rupare(o1, o2);
}
if (comparison != 0) {
return directive.direction == DESCENDING ? -comparison : comparison;
}
}
return 0;
}
}
private TableModelListener tableModelListener = new TableModelListener (){
public void tableChanged(TableModelEvent e) {
// If we"re not sorting by anything, just pass the event along.
if (!isSorting()) {
clearSortingState();
fireTableChanged(e);
return;
}
// If the table structure has changed, cancel the sorting; the
// sorting columns may have been either moved or deleted from
// the model.
if (e.getFirstRow() == TableModelEvent.HEADER_ROW) {
cancelSorting();
fireTableChanged(e);
return;
}
// We can map a cell event through to the view without widening
// when the following conditions apply:
//
// a) all the changes are on one row (e.getFirstRow() == e.getLastRow()) and,
// b) all the changes are in one column (column != TableModelEvent.ALL_COLUMNS) and,
// c) we are not sorting on that column (getSortingStatus(column) == NOT_SORTED) and,
// d) a reverse lookup will not trigger a sort (modelToView != null)
//
// Note: INSERT and DELETE events fail this test as they have column == ALL_COLUMNS.
//
// The last check, for (modelToView != null) is to see if modelToView
// is already allocated. If we don"t do this check; sorting can become
// a performance bottleneck for applications where cells
// change rapidly in different parts of the table. If cells
// change alternately in the sorting column and then outside of
// it this class can end up re-sorting on alternate cell updates -
// which can be a performance problem for large tables. The last
// clause avoids this problem.
int column = e.getColumn();
if (e.getFirstRow() == e.getLastRow()
&& column != TableModelEvent.ALL_COLUMNS
&& getSortingStatus(column) == NOT_SORTED
&& modelToView != null) {
int viewIndex = getModelToView()[e.getFirstRow()];
fireTableChanged(new TableModelEvent(TableSorter.this,
viewIndex, viewIndex,
column, e.getType()));
return;
}
// Something has happened to the data that may have invalidated the row order.
clearSortingState();
fireTableDataChanged();
return;
}
};
private MouseAdapter mouseListener_ = new MouseAdapter (){
public void mouseClicked(MouseEvent e) {
JTableHeader h = (JTableHeader) e.getSource();
TableColumnModel columnModel = h.getColumnModel();
int viewColumn = columnModel.getColumnIndexAtX(e.getX());
int column = columnModel.getColumn(viewColumn).getModelIndex();
if (column != -1) {
int status = getSortingStatus(column);
if (!e.isControlDown()) {
cancelSorting();
}
// Cycle the sorting states through {NOT_SORTED, ASCENDING, DESCENDING} or
// {NOT_SORTED, DESCENDING, ASCENDING} depending on whether shift is pressed.
status = status + (e.isShiftDown() ? -1 : 1);
status = (status + 4) % 3 - 1; // signed mod, returning {-1, 0, 1}
setSortingStatus(column, status);
}
}
};
private static class Arrow implements Icon {
private boolean descending;
private int size;
private int priority;
public Arrow(boolean descending, int size, int priority) {
this.descending = descending;
this.size = size;
this.priority = priority;
}
public void paintIcon(Component c, Graphics g, int x, int y) {
Color color = c == null ? Color.GRAY : c.getBackground();
// In a compound sort, make each succesive triangle 20%
// smaller than the previous one.
int dx = (int)(size/2*Math.pow(0.8, priority));
int dy = descending ? dx : -dx;
// Align icon (roughly) with font baseline.
y = y + 5*size/6 + (descending ? -dy : 0);
int shift = descending ? 1 : -1;
g.translate(x, y);
// Right diagonal.
g.setColor(color.darker());
g.drawLine(dx / 2, dy, 0, 0);
g.drawLine(dx / 2, dy + shift, 0, shift);
// Left diagonal.
g.setColor(color.brighter());
g.drawLine(dx / 2, dy, dx, 0);
g.drawLine(dx / 2, dy + shift, dx, shift);
// Horizontal line.
if (descending) {
g.setColor(color.darker().darker());
} else {
g.setColor(color.brighter().brighter());
}
g.drawLine(dx, 0, 0, 0);
g.setColor(color);
g.translate(-x, -y);
}
public int getIconWidth() {
return size;
}
public int getIconHeight() {
return size;
}
}
private class SortableHeaderRenderer implements TableCellRenderer {
private TableCellRenderer tableCellRenderer;
public SortableHeaderRenderer(TableCellRenderer tableCellRenderer) {
this.tableCellRenderer = tableCellRenderer;
}
public Component getTableCellRendererComponent(JTable table,
Object value,
boolean isSelected,
boolean hasFocus,
int row,
int column) {
Component c = tableCellRenderer.getTableCellRendererComponent(table,
value, isSelected, hasFocus, row, column);
if (c instanceof JLabel) {
JLabel l = (JLabel) c;
l.setHorizontalTextPosition(SwingConstants.LEFT);
int modelColumn = table.convertColumnIndexToModel(column);
l.setIcon(getHeaderRendererIcon(modelColumn, l.getFont().getSize()));
}
return c;
}
}
private static class Directive {
private int column;
private int direction;
public Directive(int column, int direction) {
this.column = column;
this.direction = direction;
}
}
//
// compatibility with the old SUN TableSorter
//
private class NewTableModel extends DefaultTableModel{
Class [] classes_;
boolean [] editable_;
public NewTableModel( String cols[], Class classes[], boolean editable[])
{
super( cols, 0 );
classes_ = classes;
if( editable != null )
editable_ = editable;
else
{
editable_ = new boolean[cols.length];
for(int i = 0; i < cols.length; i++)
editable_[i] = false;
}
}
public Class getColumnClass(int column) {
return classes_[column];
}
public boolean isCellEditable(int rowIndex, int columnIndex)
{
return(editable_[columnIndex]);
}
}
public TableSorter( String cols[], Class classes[], boolean editable[])
{
setTableModel(new NewTableModel(cols,classes, editable));
}
public TableSorter( String cols[], Class classes[])
{
setTableModel(new NewTableModel(cols,classes, null));
}
/**
* @param table1
*/
public void addMouseListenerToHeaderInTable(JTable table1) {
table1.setColumnSelectionAllowed(false);
setTableHeader(table1.getTableHeader());
}
/**
* @param ro
*/
public void addRow(Object[] ro) {
DefaultTableModel tm = (DefaultTableModel) getTableModel();
tm.addRow(ro);
fireTableDataChanged();
}
public void removeRow(int row) { // NO_UCD
DefaultTableModel tm = (DefaultTableModel) getTableModel();
tm.removeRow(row);
fireTableDataChanged();
}
/**
* @param event
*/
public void tableChanged(TableModelEvent event) {
NewTableModel tm = (NewTableModel) getTableModel();
tm.fireTableChanged(event);
fireTableDataChanged();
}
/**
* @param i
*/
public void setRowCount(int i) {
DefaultTableModel tm = (DefaultTableModel) getTableModel();
tm.setRowCount(i);
fireTableDataChanged();
}
/**
* @param i
*/
public void sortByColumn(int i) {
setSortingStatus(i, ASCENDING);
}
/**
* @param index
* @return
*/
public int getMappedIndex(int index) {
return( modelIndex(index));
}
/**
* @return
*/
public boolean isSorted() {
return isSorting();
}
/**
*
*/
public void sort() {
fireTableDataChanged();
}
}
TableSorter is a decorator for TableModels
import java.util.ArrayList;
import java.util.Arrays;
import java.util.ruparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.awt.Color;
import java.awt.ruponent;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.Icon;
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;
/**
* TableSorter is a decorator for TableModels; adding sorting
* functionality to a supplied TableModel. TableSorter does
* not store or copy the data in its TableModel; instead it maintains
* a map from the row indexes of the view to the row indexes of the
* model. As requests are made of the sorter (like getValueAt(row, col))
* they are passed to the underlying model after the row numbers
* have been translated via the internal mapping array. This way,
* the TableSorter appears to hold another copy of the table
* with the rows in a different order.
* <p/>
* TableSorter registers itself as a listener to the underlying model,
* just as the JTable itself would. Events recieved from the model
* are examined, sometimes manipulated (typically widened), and then
* passed on to the TableSorter"s listeners (typically the JTable).
* If a change to the model has invalidated the order of TableSorter"s
* rows, a note of this is made and the sorter will resort the
* rows the next time a value is requested.
* <p/>
* When the tableHeader property is set, either by using the
* setTableHeader() method or the two argument constructor, the
* table header may be used as a complete UI for TableSorter.
* The default renderer of the tableHeader is decorated with a renderer
* that indicates the sorting status of each column. In addition,
* a mouse listener is installed with the following behavior:
* <ul>
* <li>
* Mouse-click: Clears the sorting status of all other columns
* and advances the sorting status of that column through three
* values: {NOT_SORTED, ASCENDING, DESCENDING} (then back to
* NOT_SORTED again).
* <li>
* SHIFT-mouse-click: Clears the sorting status of all other columns
* and cycles the sorting status of the column through the same
* three values, in the opposite order: {NOT_SORTED, DESCENDING, ASCENDING}.
* <li>
* CONTROL-mouse-click and CONTROL-SHIFT-mouse-click: as above except
* that the changes to the column do not cancel the statuses of columns
* that are already sorting - giving a way to initiate a compound
* sort.
* </ul>
* <p/>
* This is a long overdue rewrite of a class of the same name that
* first appeared in the swing table demos in 1997.
*
* @author Philip Milne
* @author Brendon McLean
* @author Dan van Enckevort
* @author Parwinder Sekhon
* @version 2.0 02/27/04
*/
public class TableSorter extends AbstractTableModel {
protected TableModel tableModel;
public static final int DESCENDING = -1;
public static final int NOT_SORTED = 0;
public static final int ASCENDING = 1;
private static Directive EMPTY_DIRECTIVE = new Directive(-1, NOT_SORTED);
public static final Comparator COMPARABLE_COMPARATOR = new Comparator() {
public int compare(Object o1, Object o2) {
if (o1 == o2) {
return 0;
}
if (o1 == null) {
if (o2 == null) {
return 0;
}
return -1;
}
if (o2 == null) {
return 1;
}
return ((Comparable) o1).rupareTo(o2);
}
};
public static final Comparator LEXICAL_COMPARATOR = new Comparator() {
public int compare(Object o1, Object o2) {
return o1.toString().rupareTo(o2.toString());
}
};
private Row[] viewToModel;
private int[] modelToView;
private JTableHeader tableHeader;
private MouseListener mouseListener;
private TableModelListener tableModelListener;
private Map columnComparators = new HashMap();
private List sortingColumns = new ArrayList();
public TableSorter() {
this.mouseListener = new MouseHandler();
this.tableModelListener = new TableModelHandler();
}
public TableSorter(TableModel tableModel) {
this();
setTableModel(tableModel);
}
public TableSorter(TableModel tableModel, JTableHeader tableHeader) {
this();
setTableHeader(tableHeader);
setTableModel(tableModel);
}
private void clearSortingState() {
viewToModel = null;
modelToView = null;
}
public TableModel getTableModel() {
return tableModel;
}
public void setTableModel(TableModel tableModel) {
if (this.tableModel != null) {
this.tableModel.removeTableModelListener(tableModelListener);
}
this.tableModel = tableModel;
if (this.tableModel != null) {
this.tableModel.addTableModelListener(tableModelListener);
}
clearSortingState();
fireTableStructureChanged();
}
public JTableHeader getTableHeader() {
return tableHeader;
}
public void setTableHeader(JTableHeader tableHeader) {
if (this.tableHeader != null) {
this.tableHeader.removeMouseListener(mouseListener);
TableCellRenderer defaultRenderer =
this.tableHeader.getDefaultRenderer();
if (defaultRenderer instanceof SortableHeaderRenderer) {
this.tableHeader.setDefaultRenderer(
((SortableHeaderRenderer) defaultRenderer)
.tableCellRenderer);
}
}
this.tableHeader = tableHeader;
if (this.tableHeader != null) {
this.tableHeader.addMouseListener(mouseListener);
this.tableHeader.setDefaultRenderer(
new SortableHeaderRenderer(
this.tableHeader.getDefaultRenderer()));
}
}
public boolean isSorting() {
return sortingColumns.size() != 0;
}
private Directive getDirective(int column) {
for (int i = 0; i < sortingColumns.size(); i++) {
Directive directive = (Directive) sortingColumns.get(i);
if (directive.column == column) {
return directive;
}
}
return EMPTY_DIRECTIVE;
}
public int getSortingStatus(int column) {
return getDirective(column).direction;
}
private void sortingStatusChanged() {
clearSortingState();
fireTableDataChanged();
if (tableHeader != null) {
tableHeader.repaint();
}
}
public void setSortingStatus(int column, int status) {
Directive directive = getDirective(column);
if (directive != EMPTY_DIRECTIVE) {
sortingColumns.remove(directive);
}
if (status != NOT_SORTED) {
sortingColumns.add(new Directive(column, status));
}
sortingStatusChanged();
}
protected Icon getHeaderRendererIcon(int column, int size) {
Directive directive = getDirective(column);
if (directive == EMPTY_DIRECTIVE) {
return null;
}
return new Arrow(directive.direction == DESCENDING, size,
sortingColumns.indexOf(directive));
}
private void cancelSorting() {
sortingColumns.clear();
sortingStatusChanged();
}
public void setColumnComparator(Class type, Comparator comparator) {
if (comparator == null) {
columnComparators.remove(type);
} else {
columnComparators.put(type, comparator);
}
}
protected Comparator getComparator(int column) {
Class columnType = tableModel.getColumnClass(column);
Comparator comparator =
(Comparator) columnComparators.get(columnType);
if (comparator != null) {
return comparator;
}
if (Comparable.class.isAssignableFrom(columnType)) {
return COMPARABLE_COMPARATOR;
}
return LEXICAL_COMPARATOR;
}
private Row[] getViewToModel() {
if (viewToModel == null) {
int tableModelRowCount = tableModel.getRowCount();
viewToModel = new Row[tableModelRowCount];
for (int row = 0; row < tableModelRowCount; row++) {
viewToModel[row] = new Row(row);
}
if (isSorting()) {
Arrays.sort(viewToModel);
}
}
return viewToModel;
}
public int modelIndex(int viewIndex) {
return getViewToModel()[viewIndex].modelIndex;
}
private int[] getModelToView() {
if (modelToView == null) {
int n = getViewToModel().length;
modelToView = new int[n];
for (int i = 0; i < n; i++) {
modelToView[modelIndex(i)] = i;
}
}
return modelToView;
}
// TableModel interface methods
public int getRowCount() {
return (tableModel == null) ? 0
: tableModel.getRowCount();
}
public int getColumnCount() {
return (tableModel == null) ? 0
: tableModel.getColumnCount();
}
public String getColumnName(int column) {
return tableModel.getColumnName(column);
}
public Class getColumnClass(int column) {
return tableModel.getColumnClass(column);
}
public boolean isCellEditable(int row, int column) {
return tableModel.isCellEditable(modelIndex(row), column);
}
public Object getValueAt(int row, int column) {
return tableModel.getValueAt(modelIndex(row), column);
}
public void setValueAt(Object aValue, int row, int column) {
tableModel.setValueAt(aValue, modelIndex(row), column);
}
// Helper classes
private class Row implements Comparable {
private int modelIndex;
public Row(int index) {
this.modelIndex = index;
}
public int compareTo(Object o) {
int row1 = modelIndex;
int row2 = ((Row) o).modelIndex;
for (Iterator it = sortingColumns.iterator(); it.hasNext(); ) {
Directive directive = (Directive) it.next();
int column = directive.column;
Object o1 = tableModel.getValueAt(row1, column);
Object o2 = tableModel.getValueAt(row2, column);
int comparison = 0;
// Define null less than everything, except null.
if (o1 == null && o2 == null) {
comparison = 0;
} else if (o1 == null) {
comparison = -1;
} else if (o2 == null) {
comparison = 1;
} else {
comparison = getComparator(column).rupare(o1, o2);
}
if (comparison != 0) {
return directive.direction == DESCENDING ? -comparison
: comparison;
}
}
return 0;
}
}
private class TableModelHandler implements TableModelListener {
public void tableChanged(TableModelEvent e) {
// If we"re not sorting by anything, just pass the event along.
if (!isSorting()) {
clearSortingState();
fireTableChanged(e);
return;
}
// If the table structure has changed, cancel the sorting; the
// sorting columns may have been either moved or deleted from
// the model.
if (e == null || e.getFirstRow() == TableModelEvent.HEADER_ROW) {
cancelSorting();
fireTableChanged(e);
return;
}
// We can map a cell event through to the view without widening
// when the following conditions apply:
//
// a) all the changes are on one row (e.getFirstRow() == e.getLastRow()) and,
// b) all the changes are in one column (column != TableModelEvent.ALL_COLUMNS) and,
// c) we are not sorting on that column (getSortingStatus(column) == NOT_SORTED) and,
// d) a reverse lookup will not trigger a sort (modelToView != null)
//
// Note: INSERT and DELETE events fail this test as they have column == ALL_COLUMNS.
//
// The last check, for (modelToView != null) is to see if modelToView
// is already allocated. If we don"t do this check; sorting can become
// a performance bottleneck for applications where cells
// change rapidly in different parts of the table. If cells
// change alternately in the sorting column and then outside of
// it this class can end up re-sorting on alternate cell updates -
// which can be a performance problem for large tables. The last
// clause avoids this problem.
int column = e.getColumn();
if (e.getFirstRow() == e.getLastRow()
&& column != TableModelEvent.ALL_COLUMNS
&& getSortingStatus(column) == NOT_SORTED
&& modelToView != null) {
int viewIndex = getModelToView()[e.getFirstRow()];
fireTableChanged(new TableModelEvent(TableSorter.this,
viewIndex, viewIndex,
column, e.getType()));
return;
}
// Something has happened to the data that may have invalidated the row order.
clearSortingState();
fireTableDataChanged();
return;
}
}
private class MouseHandler extends MouseAdapter {
public void mouseClicked(MouseEvent e) {
JTableHeader h = (JTableHeader) e.getSource();
TableColumnModel columnModel = h.getColumnModel();
int viewColumn = columnModel.getColumnIndexAtX(e.getX());
int column = columnModel.getColumn(viewColumn).getModelIndex();
if (column != -1) {
int status = getSortingStatus(column);
if (!e.isControlDown()) {
cancelSorting();
}
// Cycle the sorting states through {NOT_SORTED, ASCENDING, DESCENDING} or
// {NOT_SORTED, DESCENDING, ASCENDING} depending on whether shift is pressed.
status = status + (e.isShiftDown() ? -1
: 1);
status = (status + 4) % 3 - 1; // signed mod, returning {-1, 0, 1}
setSortingStatus(column, status);
}
}
}
private static class Arrow implements Icon {
private boolean descending;
private int size;
private int priority;
public Arrow(boolean descending, int size, int priority) {
this.descending = descending;
this.size = size;
this.priority = priority;
}
public void paintIcon(Component c, Graphics g, int x, int y) {
Color color = c == null ? Color.gray
: c.getBackground();
// In a compound sort, make each succesive triangle 20%
// smaller than the previous one.
int dx = (int) (size / 2 * Math.pow(0.8, priority));
int dy = descending ? dx
: -dx;
// Align icon (roughly) with font baseline.
y = y + 5 * size / 6 + (descending ? -dy
: 0);
int shift = descending ? 1
: -1;
g.translate(x, y);
// Right diagonal.
g.setColor(color.darker());
g.drawLine(dx / 2, dy, 0, 0);
g.drawLine(dx / 2, dy + shift, 0, shift);
// Left diagonal.
g.setColor(color.brighter());
g.drawLine(dx / 2, dy, dx, 0);
g.drawLine(dx / 2, dy + shift, dx, shift);
// Horizontal line.
if (descending) {
g.setColor(color.darker().darker());
} else {
g.setColor(color.brighter().brighter());
}
g.drawLine(dx, 0, 0, 0);
g.setColor(color);
g.translate(-x, -y);
}
public int getIconWidth() {
return size;
}
public int getIconHeight() {
return size;
}
}
private class SortableHeaderRenderer implements TableCellRenderer {
private TableCellRenderer tableCellRenderer;
public SortableHeaderRenderer(TableCellRenderer tableCellRenderer) {
this.tableCellRenderer = tableCellRenderer;
}
public Component getTableCellRendererComponent(JTable table,
Object value, boolean isSelected, boolean hasFocus, int row,
int column) {
Component c =
tableCellRenderer.getTableCellRendererComponent(table, value,
isSelected, hasFocus, row, column);
if (c instanceof JLabel) {
JLabel l = (JLabel) c;
l.setHorizontalTextPosition(JLabel.LEFT);
int modelColumn = table.convertColumnIndexToModel(column);
l.setIcon(getHeaderRendererIcon(modelColumn,
l.getFont().getSize()));
}
return c;
}
}
private static class Directive {
private int column;
private int direction;
public Directive(int column, int direction) {
this.column = column;
this.direction = direction;
}
}
}
Table with a custom TableModel
/* From http://java.sun.ru/docs/books/tutorial/index.html */
/*
* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* -Redistribution of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* -Redistribution in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
* ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
* OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN")
* AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
* AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
* DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
* REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
* INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
* OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*
* You acknowledge that this software is not designed, licensed or intended
* for use in the design, construction, operation or maintenance of any
* nuclear facility.
*/
/*
* TableDemo.java is a 1.4 application that requires no other files.
*/
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
import java.awt.Dimension;
import java.awt.GridLayout;
/**
* TableDemo is just like SimpleTableDemo, except that it uses a custom
* TableModel.
*/
public class TableDemo extends JPanel {
private boolean DEBUG = false;
public TableDemo() {
super(new GridLayout(1, 0));
JTable table = new JTable(new MyTableModel());
table.setPreferredScrollableViewportSize(new Dimension(500, 70));
//Create the scroll pane and add the table to it.
JScrollPane scrollPane = new JScrollPane(table);
//Add the scroll pane to this panel.
add(scrollPane);
}
class MyTableModel extends AbstractTableModel {
private String[] columnNames = { "First Name", "Last Name", "Sport",
"# of Years", "Vegetarian" };
private Object[][] data = {
{ "Mary", "Campione", "Snowboarding", new Integer(5),
new Boolean(false) },
{ "Alison", "Huml", "Rowing", new Integer(3), new Boolean(true) },
{ "Kathy", "Walrath", "Knitting", new Integer(2),
new Boolean(false) },
{ "Sharon", "Zakhour", "Speed reading", new Integer(20),
new Boolean(true) },
{ "Philip", "Milne", "Pool", new Integer(10),
new Boolean(false) } };
public int getColumnCount() {
return columnNames.length;
}
public int getRowCount() {
return data.length;
}
public String getColumnName(int col) {
return columnNames[col];
}
public Object getValueAt(int row, int col) {
return data[row][col];
}
/*
* JTable uses this method to determine the default renderer/ editor for
* each cell. If we didn"t implement this method, then the last column
* would contain text ("true"/"false"), rather than a check box.
*/
public Class getColumnClass(int c) {
return getValueAt(0, c).getClass();
}
/*
* Don"t need to implement this method unless your table"s editable.
*/
public boolean isCellEditable(int row, int col) {
//Note that the data/cell address is constant,
//no matter where the cell appears onscreen.
if (col < 2) {
return false;
} else {
return true;
}
}
/*
* Don"t need to implement this method unless your table"s data can
* change.
*/
public void setValueAt(Object value, int row, int col) {
if (DEBUG) {
System.out.println("Setting value at " + row + "," + col
+ " to " + value + " (an instance of "
+ value.getClass() + ")");
}
data[row][col] = value;
fireTableCellUpdated(row, col);
if (DEBUG) {
System.out.println("New value of data:");
printDebugData();
}
}
private void printDebugData() {
int numRows = getRowCount();
int numCols = getColumnCount();
for (int i = 0; i < numRows; i++) {
System.out.print(" row " + i + ":");
for (int j = 0; j < numCols; j++) {
System.out.print(" " + data[i][j]);
}
System.out.println();
}
System.out.println("--------------------------");
}
}
/**
* Create the GUI and show it. For thread safety, this method should be
* invoked from the event-dispatching thread.
*/
private static void createAndShowGUI() {
//Make sure we have nice window decorations.
JFrame.setDefaultLookAndFeelDecorated(true);
//Create and set up the window.
JFrame frame = new JFrame("TableDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Create and set up the content pane.
TableDemo newContentPane = new TableDemo();
newContentPane.setOpaque(true); //content panes must be opaque
frame.setContentPane(newContentPane);
//Display the window.
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
//Schedule a job for the event-dispatching thread:
//creating and showing this application"s GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
Use model to control the Editable Columns
/*
Definitive Guide to Swing for Java 2, Second Edition
By John Zukowski
ISBN: 1-893115-78-X
Publisher: APress
*/
import java.awt.BorderLayout;
import java.util.Date;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableModel;
public class EditableColumn {
public static void main(String args[]) {
TableModel model = new AbstractTableModel() {
Icon icon1 = new ImageIcon("TreeCollapsed.gif");
Icon icon2 = new ImageIcon("TreeExpanded.gif");
Object rowData[][] = {
{ new Integer(1), "ichi", Boolean.TRUE,
new Date("01/01/2000"), icon1 },
{ new Integer(2), "ni", Boolean.TRUE,
new Date("04/15/1999"), icon2 },
{ new Integer(3), "san", Boolean.FALSE,
new Date("12/07/1941"), icon2 },
{ new Integer(4), "shi", Boolean.TRUE,
new Date("02/29/2000"), icon1 },
{ new Integer(5), "go", Boolean.FALSE,
new Date("05/23/1995"), icon1 }, };
String columnNames[] = { "English", "Japanese", "Boolean", "Date",
"ImageIcon" };
public int getColumnCount() {
return columnNames.length;
}
public String getColumnName(int column) {
return columnNames[column];
}
public int getRowCount() {
return rowData.length;
}
public Object getValueAt(int row, int column) {
return rowData[row][column];
}
public Class getColumnClass(int column) {
return (getValueAt(0, column).getClass());
}
public void setValueAt(Object value, int row, int column) {
rowData[row][column] = value;
}
public boolean isCellEditable(int row, int column) {
return (column != 4);
}
};
JFrame frame = new JFrame("Column Renderer Table");
JTable table = new JTable(model);
JScrollPane scrollPane = new JScrollPane(table);
frame.getContentPane().add(scrollPane, BorderLayout.CENTER);
frame.setSize(400, 150);
frame.setVisible(true);
}
}