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