Article View: borland.public.jbuilder.java.swing
Article #12991Re: Colunn Headers for Jtable
From: Vladimir Olenin
Date: Mon, 05 Oct 1998 00:00
Date: Mon, 05 Oct 1998 00:00
1351 lines
43802 bytes
43802 bytes
This is a multi-part message in MIME format.
--------------890D83D4D05AB925FF0B2E98
Content-Type: text/plain; charset=koi8-r
Content-Transfer-Encoding: 7bit
Well, actually it's pretty simple. As usual in Swing u just need to
override some Model class to customize a component. So, here is an
example:
////////////////////////////////////////////////////////////////////////////////
class CustomTableModel extends AbstractTableModel{
Object[][] data;
String[] columnNames = {"Property", "Value"};
CustomTableModel(String[] prop){ // The constructor
might be empty as well,
data = new Object[prop.length][2]; // if i'm not mistaken
for(int row = 0; row < prop.length; row++)
setValueAt(prop[row], row, 0);
}
public int getColumnCount(){
return columnNames.length;
}
public int getRowCount(){
return data.length;
}
public String getColumnName(int col){
return columnNames[col];
}
/*
public Class getColumnClass(int c){
return getValueAt(0, c).getClass();
}
*/
public boolean isCellEditable(int row, int col){
return false;
}
public void setValueAt(Object value, int row, int col){
data[row][col] = value;
}
public Object getValueAt(int row, int col){
return data[row][col];
}
}
////////////////////////////////////////////////////////////////////////////////
To construct JTable itself, type this string:
JTable table = new JTable(serverModel); //serverModel is an instance of
CustomTableModel
Just want to add another thing: read through JavaSoft Swing tutorial!
U'll find it to be VERY useful. I've attached the page of this tutorial
concerning the problem of customizing JTable components. All the best,
Vladimir Olenin
Steve McAtee wrote:
>
> I'm attempting to do this and having little luck. Does anyone have example
> code of how to set a header for a column on the Jtable class.
>
> Thanks
--------------890D83D4D05AB925FF0B2E98
Content-Type: text/html; charset=koi8-r;
name="table.html"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="table.html"
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<!--NewPage-->
<html>
<head>
<title>How to Use Tables</title>
</head>
<body BGCOLOR="#ffffff">
<table width="100%">
<tr>
<td align=left>
<a href="tabbedpane.html"><img src="../../images/PreviousArrow.gif" width=26 height=26 align=bottom border=0 alt="Previous | "></a><a
href="text.html"><img src="../../images/NextArrow.gif" width=26 height=26 align=bottom border=0 alt="Next | "></a><a
href="../../trailmap.html"><img src="../../images/WayUpArrow.gif" width=26 height=26 align=bottom border=0 alt="Trail Map | "></a><a
href="../index.html"><img src="../../images/uiHeader.gif" width=26 height=26 align=bottom border=0 alt="Creating a User Interface | "></a>
</td>
<td align=right>
<a href="index.html"><strong><em>Using the JFC/Swing Packages</em></strong></a>
</td>
</tr>
</table>
<p>
<center>
<IMG SRC="../../images/shoeline2.GIF" ALIGN="BOTTOM" BORDER="0" WIDTH="202"
HEIGHT="25" NATURALSIZEFLAG="3">
<IMG SRC="../../images/shoeline2.GIF" ALIGN="BOTTOM" BORDER="0" WIDTH="202"
HEIGHT="25" NATURALSIZEFLAG="3">
</center>
<p>
<h2>
How to Use Tables
</h2>
<p>
<blockquote>
With the
<a target="_top" href="http://java.sun.com/products/jfc/swingdoc-api/com/sun/java/swing/JTable.html"><code>JTable</code></a><a target="_top" href="http://java.sun.com/products/jfc/swingdoc-api/com/sun/java/swing/JTable.html"><img src="../../images/apiIcon.gif" width=20 height=20 border=0 alt="(in the API reference documentation)"></a> class,
you can display tables of data,
optionally allowing the user to edit the data.
<code>JTable</code> doesn't contain or cache data;
it's simply a view of your data.
Here's a picture of a typical table
displayed within a scroll pane:
<blockquote><IMG SRC="../../figures/ui/TableDemo.gif" WIDTH="528" HEIGHT="120" ALIGN="BOTTOM" NATURALSIZEFLAG="3" ALT=""></blockquote>
[PENDING: Label these parts: each cell displays an item of data;
the column header displays the column name;
maybe: each column contains one type of data]
<p>
The rest of this section tells you how to accomplish
some common table-related tasks.
Because <code>JTable</code>
has too many features
to be completely described in this tutorial,
please periodically search
<a href="http://java.sun.com/products/jfc/swingdoc-current/">The Swing
Connection</a> for pointers to other table documentation.
Here are the topics this section covers:
<ul>
<li> <a href="#simple">Creating a Simple Table</a>
<li> <a href="#show">Adding a Table to a Container</a>
<li> <a href="#width">Setting and Changing Column Widths</a>
<li> <a href="#selection">Detecting User Selections</a>
<li> <a href="#data">Creating a Table Model</a>
<li> <a href="#modelchange">Detecting Data Changes</a>
<li> <a href="#editrender">Concepts: Cell Editors and Renderers</a>
<li> <a href="#validtext">Validating User-Entered Text</a>
<li> <a href="#combobox">Using a Combo Box as an Editor</a>
<li> <a href="#editor">Specifying Other Editors</a>
<li> <a href="#custom">Further Customizing the Display and Event Handling</a>
<li> <a href="#sorting">Sorting and Otherwise Manipulating Data</a>
<li> <a href="#api">The Table API</a>
<li> <a href="#eg">Examples that Use Tables</a>
</ul>
<h4>
<a name="simple">Creating a Simple Table</a>
</h4>
<blockquote>
<blockquote><IMG SRC="../../figures/ui/SimpleTableDemo.gif" WIDTH="529" HEIGHT="116" ALIGN="BOTTOM" NATURALSIZEFLAG="3" ALT="SimpleTableDemo"></blockquote>
<blockquote>
<hr>
<strong>Try this:</strong>
<ol>
<li> Compile and run SimpleTableDemo.
The source file is
<a href="example-swing/SimpleTableDemo.java"><code>SimpleTableDemo.java</code></a>.
<br>
See <a href="swingStart.html">Getting Started with Swing</a>
if you need help.
<li> Click the cell that contains "Snowboarding".
<br>
The entire first row is selected,
indicating that you have selected Mary Campione's data.
If you don't want row selection,
you can specify a different selection model using the
<code>JTable</code>
<code>setCellSelectionEnabled</code>
or
<code>setColumnSelectionAllowed</code>
method.
A special highlight indicates that the "Snowboarding" cell
is editable.
Generally, you begin editing a text cell by double-clicking it.
<li> Position the cursor over the "First Name" heading.
Now press the mouse button
and drag the heading to the right.
<br>
As you can see,
users can rearrange columns in tables.
<li> Position the cursor just to the right
of a heading.
Now press the mouse button and drag to the right or left.
<br>
The column changes size,
and the other columns adjust to fill the remaining space.
<li> Resize the window containing the table
so that it's bigger than necessary to display the whole table.
<br>
All the table cells become larger,
expanding to fill the extra space.
</ol>
<hr>
</blockquote>
Here is the code that implements
the table in
<a href="example-swing/SimpleTableDemo.java"><code>SimpleTableDemo.java</code></a>:
<blockquote>
<pre>
Object[][] data = {
{"Mary", "Campione",
"Snowboarding", new Integer(5), new Boolean(false)},
{"Alison", "Huml",
"Rowing", new Integer(3), new Boolean(true)},
{"Kathy", "Walrath",
"Chasing toddlers", new Integer(2), new Boolean(false)},
{"Mark", "Andrews",
"Speed reading", new Integer(20), new Boolean(true)},
{"Angela", "Lih",
"Teaching high school", new Integer(4), new Boolean(false)}
};
String[] columnNames = {"First Name",
"Last Name",
"Sport",
"# of Years",
"Vegetarian"};
final JTable table = new JTable(data, columnNames);
</pre>
</blockquote>
The SimpleTableDemo example uses one of two <code>JTable</code>
constructors that directly accept data:
<ul>
<li> <code>JTable(Object[][] rowData, Object[] columnNames)</code>
<li> <code>JTable(Vector rowData, Vector columnNames)</code>
</ul>
The advantage of using one of these constructors is that it's easy.
However, these constructors also have disadvantages:
<ul>
<li> They automatically make every cell editable.
<li> They treat all data types the same.
For example, if a table column has <code>Boolean</code> data,
the table can display the data in a check box.
However, if you use one of the data-accepting
<code>JTable</code> constructors,
your <code>Boolean</code> data will be displayed as a String.
You can see this difference
in the last column of the two previous pictures of tables.
<li> They require that you put all of the table's data
in the array or vector,
which isn't appropriate for some data.
For example, if you're reading data from a large database,
then you almost certainly don't want to read the whole database
and store it in an array or vector.
</ul>
If you want to get around these restrictions,
you need to implement your own table model,
as described in <a href="#data">Creating a Table Model</a>.
</blockquote>
<h4>
<a name="show">
Adding a Table to a Container
</a>
</h4>
<blockquote>
It's easy to put a table in a
<a href="scrollpane.html">scroll pane</a>.
You need just one or two lines of code:
<blockquote>
<pre>
JScrollPane scrollPane = new JScrollPane(table);
table.setPreferredScrollableViewportSize(new Dimension(500, 70));
</pre>
</blockquote>
The scroll pane automatically gets the table's header,
which displays the column names,
and puts it on top of the table.
Even when the user scrolls down,
the column names remain visible at the top of the viewing area.
The scroll table also
tries to make its viewing area
the same as the table's
preferred viewing size.
The previous code snippet sets the table's preferred viewing size with the
<code>setPreferredScrollableViewportSize</code> method.
<p>
If you're using a table without a scroll pane,
then you must get the table header component
and place it yourself.
For example:
<blockquote>
<pre>
container.setLayout(new BorderLayout());
container.add(table.getTableHeader(), BorderLayout.NORTH);
container.add(table, BorderLayout.CENTER);
</pre>
</blockquote>
</blockquote>
<h4>
<a name="width">
Setting and Changing Column Widths
</a>
</h4>
<blockquote>
By default, all columns in a table
start out with equal width,
and the columns automatically fill the entire width
of the table.
When the table becomes wider or narrower
(which might happen when the user resizes the window containing the table),
all the column widths change appropriately.
<p>
When the user resizes a column by dragging
its right border,
then either other columns must change size,
or the table's size must change.
By default, the table's size remains the same,
and all columns to the right of the drag point
resize to accommodate space added or removed
from the column to the left of the drag point.
<p>
The following figures illustrate the default resizing behavior.
<p>
<IMG SRC="../../figures/ui/SimpleTableDemo.gif" WIDTH="529" HEIGHT="116" ALT="SimpleTableDemo"><br>
<b>Initially, the columns have equal width.</b>
</p>
<p>
<IMG SRC="../../figures/ui/SimpleTableDemo-resize-0.gif" WIDTH="529" HEIGHT="116" ALT="SimpleTableDemo during resizing"><br>
[PENDING: show resize cursor between Sport and # columns]:
<br>
<b>When the user resizes a column,
some of the other
columns must adjust size for the table to stay the same size.</b>
</p>
<p>
<IMG SRC="../../figures/ui/SimpleTableDemo-resize-1.gif" WIDTH="439" HEIGHT="114" ALT="SimpleTableDemo after the entire table is resized"><br>
<b>When the entire table is resized,
all the columns are resized.</b>
</p>
<p>
To customize initial column widths,
you can invoke <code>setMinWidth</code>
on each of your table's columns.
This sets both the minimum widths of the columns and
their approximate relative widths.
For example, adding the following code to SimpleTableDemo
makes its third column bigger than the other columns:
<blockquote>
<pre>
// Implementing a flexible-width table.
TableColumn column = null;
for (int i = 0; i < 5; i++) {
column = table.getColumnModel().getColumn(i);
if (i == 2) {
column.setMinWidth(100); //sport column is bigger
} else {
column.setMinWidth(50);
}
}
</pre>
</blockquote>
<blockquote>
<hr>
<strong>Note:</strong>
If you use <code>setMinWidth</code>,
be sure to invoke it on every column.
Otherwise,
the columns you miss
will be very thin.
<hr>
</blockquote>
<p>
<blockquote>
<hr>
<strong>Note:</strong>
When the next Swing 1.1 release comes out,
change all references to
<code>setMinWidth</code>
to be to <code>setPreferredWidth</code> instead.
The <code>setPreferredWidth</code> and
<code>getPreferredWidth</code> methods
will be released for the first time
in the next Swing 1.1 release.
When the user resizes columns,
the new sizes become the columns' new preferred widths.
<hr>
</blockquote>
<p>
As the preceding code shows,
each column in a table is represented by a
<a target="_top" href="http://java.sun.com/products/jfc/swingdoc-api/com/sun/java/swing/table/TableColumn.html"><code>TableColumn</code></a><a target="_top" href="http://java.sun.com/products/jfc/swingdoc-api/com/sun/java/swing/table/TableColumn.html"><img src="../../images/apiIcon.gif" width=20 height=20 border=0 alt="(in the API reference documentation)"></a> object.
Besides <code>setMinWidth</code>,
<code>TableColumn</code> also supplies methods
for getting/setting the maximum width and current width
of a column.
[PENDING: Soon it'll have methods for getting/setting
the preferred width.]
For an example of setting cell widths
based on the actual amount of space
needed to draw the cells' contents,
see the <code>initColumnSizes</code> method in
<a
href="example-swing/TableRenderDemo.java"><code>TableRenderDemo.java</code></a>,
which is discussed in
<a href="#custom">Further Customizing the Display and Event Handling</a>.
<p>
You can change a table's resize behavior by invoking
the <code>setAutoResizeMode</code> method.
The method's argument
should have one of these values
(defined as constants in <code>JTable</code>):
<dl>
<dt> <code>AUTO_RESIZE_SUBSEQUENT_COLUMNS</code>
<dd> The default.
In addition to resizing the column
to the left of the drag point,
adjusts the sizes of all columns to the right of the drag point.
<dt> <code>AUTO_RESIZE_NEXT_COLUMN</code>
<dd> Adjusts only the columns immediately to the left and right
of the drag point.
<dt> <code>AUTO_RESIZE_OFF</code>
<dd> Adjust the table size instead.
</ul>
<blockquote>
<hr>
<strong>Note:</strong>
Before the Swing 1.1 Beta release,
the default resize mode was
<code>AUTO_RESIZE_ALL_COLUMNS</code>.
However, that mode isn't intuitive,
so we recommend against using it.
<hr>
</blockquote>
<p>
To create a fixed-width table with customized
column widths,
turn auto-resizing off
and use the <code>setWidth</code> method
to initialize the width of every column.
If the table is in a scroll pane,
be sure to set the table's preferred scrollable viewport width
to be no more than the sum of its columns' widths,
or else you'll get white space at the right edge of the table.
For example:
<blockquote>
<pre>
// Implementing a fixed-width table.
table.setPreferredScrollableViewportSize(new Dimension(425, 50));
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
for (int i = 0; i < 5; i++) {
column = table.getColumnModel().getColumn(i);
if (i == 2) {
column.setWidth(125); //sport column is bigger
} else {
column.setWidth(75);
}
}
</pre>
</blockquote>
</blockquote>
<h4>
<a name="selection">
Detecting User Selections
</a>
</h4>
<blockquote>
The following code snippet shows
how to detect when the user selects a table row.
You can find the entire program,
which demonstrates many more selection features, in
<a href="example-swing/SimpleTableSelectionDemo.java"><code>SimpleTableSelectionDemo.java</code></a>.
<blockquote>
<pre>
ListSelectionModel rowSM = table.getSelectionModel();
rowSM.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
rowSM.addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
ListSelectionModel lsm = (ListSelectionModel)e.getSource();
int selectedRow = lsm.getMinSelectionIndex();
if (selectedRow >= 0) {
<em>...//selectedRow is selected</em>
} else {
<em>...//no rows are selected</em>
}
}
});
</pre>
</blockquote>
<p>
<a
href="example-swing/SimpleTableSelectionDemo.java">SimpleTableSelectionDemo</a>
also has code
(not included in the preceding snippet)
that changes the table's selection orientation.
By copying the relevant code,
you can make the table allow either column selections
or individual cell selections,
instead of row selections.
<p>
Because tables use
<code>ListSelectionModel</code> objects
to control row and column selection,
you can easily specify which selection mode
the table uses.
For example,
the preceding code snippet
makes the row selection model
allow at most a single selection.
See <a href="listselectionlistener.html">Writing a List Selection Listener</a>
for information about and examples of
using selection modes.
</blockquote>
<h4>
<a name="data">
Creating a Table Model
</a>
</h4>
<blockquote>
As the following figure shows,
every table gets its data from an object
that implements the
<a target="_top" href="http://java.sun.com/products/jfc/swingdoc-api/com/sun/java/swing/table/TableModel.html"><code>TableModel</code></a><a target="_top" href="http://java.sun.com/products/jfc/swingdoc-api/com/sun/java/swing/table/TableModel.html"><img src="../../images/apiIcon.gif" width=20 height=20 border=0 alt="(in the API reference documentation)"></a> interface.
<pre>
[Model (TableModel)] --> [View (JTable)]
</pre>
[PENDING: make that a real figure, similar to the circle/big-arrow
one below.]
<p>
Here's the code that the data-accepting <code>JTable</code> constructor
shown previously
uses to create its table model:
<blockquote>
<pre>
new AbstractTableModel() {
public String getColumnName(int col) {
return columnNames[col].toString();
}
public int getRowCount() { return rowData.length; }
public int getColumnCount() { return columnNames.length; }
public Object getValueAt(int row, int col) {
return rowData[row][col];
}
public boolean isCellEditable(int row, int col) { return true; }
public void setValueAt(Object value, int row, int col) {
rowData[row][col] = value;
}
}
</pre>
</blockquote>
As the preceding code shows,
implementing a table model can be simple.
Generally, you implement your table model in a subclass of the
<a target="_top" href="http://java.sun.com/products/jfc/swingdoc-api/com/sun/java/swing/table/AbstractTableModel.html"><code>AbstractTableModel</code></a><a target="_top" href="http://java.sun.com/products/jfc/swingdoc-api/com/sun/java/swing/table/AbstractTableModel.html"><img src="../../images/apiIcon.gif" width=20 height=20 border=0 alt="(in the API reference documentation)"></a> class.
<p>
Your model might hold its data
in an array, vector, or hashtable,
or it might get the data from an outside source such as a database.
It might even generate the data at execution time.
For examples of getting data from a database,
see the <code>examples/Table</code>
directory in the Swing release.
<p>
Here again is a picture of a table
implemented by TableDemo,
which has a custom table model:
<blockquote><IMG SRC="../../figures/ui/TableDemo.gif" WIDTH="528" HEIGHT="120" ALIGN="BOTTOM" NATURALSIZEFLAG="3" ALT=""></blockquote>
This table is different from the SimpleTableDemo table
in the following ways:
<ul>
<li> SimpleTableDemo's table model,
having been created automatically by <code>JTable</code>,
isn't smart enough to know that the # of Years column
contains numbers (which should generally be right aligned).
It also doesn't know that the Vegetarian column
contains boolean values,
which can be represented by check boxes.
TableDemo's custom table model,
even though it's simple,
can easily determine the data's type,
helping the <code>JTable</code> display the data in the best format.
<li> In SimpleTableDemo, all cells are editable.
In TableDemo,
we implemented the custom table model
so that it doesn't let you edit the name columns;
it does, however, let you edit the other columns.
</ul>
<p>
Below is the code from
<a href=example-swing/TableDemo.java><code>TableDemo.java</code></a>
that is different from the code in
<a href=example-swing/SimpleTableDemo.java><code>SimpleTableDemo.java</code></a>.
Bold font indicates the code that makes this table's model
different from the table model defined automatically
in SimpleTableDemo.
<blockquote>
<pre>
public TableDemo() {
...
MyTableModel myModel = new MyTableModel();
JTable table = new JTable(myModel);
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 window.
setContentPane(scrollPane);
...
}
class MyTableModel extends AbstractTableModel {
final String[] columnNames = <em>...//same as before...</em>
final Object[][] data = <em>...//same as before...</em>
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];
}
<b>public Class getColumnClass(int c) {
return getValueAt(0, c).getClass();
}</b>
/*
* 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.
<b>if (col < 2) {
return false;
} else {
return true;
}</b>
}
/*
* Don't need to implement this method unless your table's
* data can change.
*/
public void setValueAt(Object value, int row, int col) {
<em>...//debugging code not shown...</em>
<b><em>...//ugly class cast code for Integers not shown...</em></b>
data[row][col] = value;
<em>...//debugging code not shown...</em>
}
...
</pre>
</blockquote>
</blockquote>
<h4>
<a name="modelchange">
Detecting Data Changes
</a>
</h4>
<blockquote>
A table and its model automatically detect
whenever the user edits the table's data.
However, if the data changes for another reason,
you must take special steps to notify the table
and its model of the data change.
Also, if you don't implement a table model,
as in SimpleTableDemo,
then you must take special steps
to find out when the user edits the table's data.
<p>
An example of updating a table's data
without directly editing it
is in the BINGO application.
The BINGO application,
which is presented in
<a target="_top" href="../../together/bingo/index.html">BINGO!</a><a target="_top" href="../../together/bingo/index.html"><img src="../../images/jdk1_1.gif" width=20 height=20 border=0 alt="(in Putting It Together trail)"></a>, has a table that displays some information
about each user who is signed up to play the game.
When a new user signs up to play BINGO,
the table needs to add a new row for that user.
More precisely,
the table model needs to get
the data for the new user,
and then the table model needs to tell the table
to display the new data.
<p>
To notify the table model about a new user,
the BINGO application
invokes the table model's <code>updatePlayer</code> method.
You can see the code for that method in
<a
href="../../together/bingo/example-swing/bingo/shared/PlayerInfoModel.java"></code><code>PlayerInfoModel.java</code></a>,
which contains the implementation of the table model.
The <code>updatePlayer</code> method records the new user's data
and fires a table-model event.
Because every table listens for table-model events
from its model,
the user-information table automatically detects the change
and displays the new data.
<p>
To fire the table-model event,
the model invokes the the <code>fireTableRowsInserted</code> method,
which is defined by the
<a target="_top" href="http://java.sun.com/products/jfc/swingdoc-api/com/sun/java/swing/table/AbstractTableModel.html"><code>AbstractTableModel</code></a><a target="_top" href="http://java.sun.com/products/jfc/swingdoc-api/com/sun/java/swing/table/AbstractTableModel.html"><img src="../../images/apiIcon.gif" width=20 height=20 border=0 alt="(in the API reference documentation)"></a> class.
Other <code>fire<em>Xxxx</em></code> methods that
<code>AbstractTableModel</code> defines
to help you fire table-model events are
<code>fireTableCellUpdated</code>,
<code>fireTableChanged</code>,
<code>fireTableDataChanged</code>,
<code>fireTableRowsDeleted</code>,
<code>fireTableRowsInserted</code>,
<code>fireTableRowsUpdated</code>, and
<code>fireTableStructureChanged</code>.
See [PENDING: API table] for information about these methods.
<p>
If you have a program such as SimpleTableDemo
that doesn't implement a table model,
then you need to do something special
to find out when the user edits the table's data.
Specifically, you need to register
a table-model listener on the table model.
Here is code,
taken from
<a
href="example-swing/SimpleTableEditDemo.java"><code>SimpleTableEditDemo.java</code></a>,
that registers a table-model listener
and reacts to events:
<blockquote>
<pre>
public class SimpleTableEditDemo ... implements TableModelListener {
...
public SimpleTableEditDemo() {
...
model = table.getModel();
model.addTableModelListener(this);
...
}
public void tableChanged(TableModelEvent e) {
...
int row = e.getFirstRow();
int column = e.getColumn();
String columnName = model.getColumnName(column);
Object data = model.getValueAt(row, column);
<em>...// Do something with the data...</em>
}
...
}
</pre>
</blockquote>
<p>
</blockquote>
<h4>
<a name="editrender">
Concepts: Cell Editors and Renderers
</a>
</h4>
<blockquote>
Before you go on to the next few tasks,
you need to understand how tables draw their cells.
You might expect each cell in a table to be a component.
However, for performance reasons,
Swing tables aren't implemented that way.
Instead, each column has a single
<em>cell renderer</em>
that draws all of its cells.
You can think of the renderer as a
configurable ink stamp
that the table uses to
stamp appropriately formatted data onto each cell.
When the user starts to edit a cell's data,
a <em>cell editor</em>
controls the cell's editing behavior.
<p>
For example, each cell in the # of Years column in TableDemo
contains <code>Number</code> data --
specifically, an <code>Integer</code> object.
By default, the cell renderer for a <code>Number</code>-containing column
uses a single <code>JLabel</code> instance
to draw the appropriate numbers, right-aligned,
on the column's cells.
If the user begins editing one of the cells,
the default cell editor
uses a right-aligned <code>JTextField</code>
to control the cell editing.
<p>
The following list shows the components that a table uses
to render and edit the specified kinds of data.
The table gets the column data type
by invoking the <code>getColumnClass</code> method
on the table model.
Remember that if you let <code>JTable</code>
create its own model,
it uses <code>Object</code>
as the type of every column.
<a href=example-swing/TableDemo.java><code>TableDemo.java</code></a>
shows how to specify more precise column types.
<p>
<table >
<tr>
<th align=left> Column Data Type
<th align=left> Default Rendering Component
<th align=left> Default Editing Component
<tr>
<td> <code>Object</code>
<td> <code>JLabel</code>
<td> <code>JTextField</code>
<tr>
<td> <code>ImageIcon</code>
<td> <code>JLabel</code>
<td> <code>JTextField</code> [PENDING: ???]
<tr>
<td> <code>Number</code>
<td> <code>JLabel</code> (right aligned)
<td> <code>JTextField</code> (right aligned)
<tr>
<td> <code>Boolean</code>
<td> <code>JCheckBox</code>
<td> <code>JCheckBox</code>
</table>
<p>
To customize cell display and editing,
you can specify different cell editors and renderers
either by column or by data type,
as described in the next couple of sections.
</blockquote>
<h4>
<a name="validtext">
Validating User-Entered Text
</a>
</h4>
<blockquote>
In the table examples you've seen so far,
the user can enter any text into the # of Years column.
SimpleTableDemo doesn't check the data's value, at all.
The TableDemo example is slightly improved
in that when the user is done editing,
the code checks whether the entry can be parsed as an integer.
However, TableDemo must use a bit of ugly code
to convert the string returned by the default cell editor
into an <code>Integer</code>.
If it didn't do the conversion,
then the actual type of the data
would change from <code>Integer</code> to <code>String</code>.
<p>
What we'd really like to do
is to check the user's input
<em>while</em> the user is typing,
and to have the cell editor return an
<code>Integer</code> instead of a string.
You can accomplish one or both of these tasks
by using a custom text field
to control the cell editing.
<p>
A custom text field
can check the user's input either
while the user is typing,
or after the user has indicated the end of typing
(such as by pressing return).
We call these two types of validation
<em>keystroke</em> checking
and <em>action</em> checking,
respectively.
<p>
The following code, taken from
<a href="example-swing/TableEditDemo.java"><code>TableEditDemo.java</code></a>,
sets up a keystroke-checking text field.
The bold line of code makes the text field
the editor for all columns
that contain data of type <code>Integer</code>.
<blockquote>
<pre>
final WholeNumberField integerField = new WholeNumberField(0, 5);
integerField.setHorizontalAlignment(WholeNumberField.RIGHT);
DefaultCellEditor integerEditor =
new DefaultCellEditor(integerField) {
//Override DefaultCellEditor's getCellEditorValue method
//to return an Integer, not a String:
public Object getCellEditorValue() {
return new Integer(integerField.getValue());
}
};
<b>table.setDefaultEditor(Integer.class, integerEditor);</b>
</pre>
</blockquote>
The <a href="example-swing/WholeNumberField.java"><code>WholeNumberField</code></a>
class used above is a custom <code>JTextField</code>
subclass that allows the user to enter only digits.
The <code>getValue</code> method
returns the <code>int</code> value of the <code>WholeNumberField</code>'s
contents.
See <a href="textfield.html">How to Use Text Fields</a>
for more information about <code>WholeNumberField</code>.
That section also provides
a more general-purpose validating text field,
called <code>DecimalField</code>,
that you can customize so that it validates
any number format that you specify.
</blockquote>
<h4>
<a name="combobox">
Using a Combo Box as an Editor
</a>
</h4>
<blockquote>
Here is an example of setting up a combo box editor.
The bold line of code
sets up the combo box as the editor for a column,
rather than for a specific data type.
<blockquote>
<pre>
TableColumn sportColumn = table.getColumnModel().getColumn(2);
...
JComboBox comboBox = new JComboBox();
comboBox.addItem("Snowboarding");
comboBox.addItem("Rowing");
comboBox.addItem("Chasing toddlers");
comboBox.addItem("Speed reading");
comboBox.addItem("Teaching high school");
comboBox.addItem("None");
<b>sportColumn.setCellEditor(new DefaultCellEditor(comboBox));</b>
</pre>
</blockquote>
Here is a picture of the combo box editor in use:
<blockquote><IMG SRC="../../figures/ui/TableRenderDemo.gif" WIDTH="529" HEIGHT="159" ALIGN="BOTTOM" NATURALSIZEFLAG="3" ALT="A combo box cell editor in use"></blockquote>
The combo box editor is implemented in
<a href="example-swing/TableRenderDemo.java"><code>TableRenderDemo.java</code></a>,
which is discussed further in
<a href="#custom">Further Customizing the Display and Event Handling</a>.
</blockquote>
<h4>
<a name="editor">
Specifying Other Editors
</a>
</h4>
<blockquote>
As the previous sections showed,
you can set the editor for an entire column
using the <code>TableColumn</code> <code>setCellEditor</code> method,
or for a specific type of data
using the <code>JTable</code>
<code>setDefaultEditor</code> method.
For both methods,
you must specify an argument that implements the <code>TableCellEditor</code>
interface.
Fortunately, the <code>DefaultCellEditor</code> class
implements this interface and provides
constructors to let you specify an editing component
that's a <code>JTextField</code>,
<code>JCheckBox</code>, or
<code>JComboBox</code>.
You usually don't have to explicitly specify a check box as an editor,
since columns with <code>Boolean</code> data
automatically use a check box renderer and editor.
<p>
What if you want to specify an editor
that isn't a text field, check box, or combo box?
Well, because <code>DefaultCellEditor</code>
doesn't support other types of components,
you must do a little more work.
You need to create a subclass of the desired editor component,
and the subclass must implement the
<a target="_top" href="http://java.sun.com/products/jfc/swingdoc-api/com/sun/java/swing/table/TableCellEditor.html"><code>TableCellEditor</code></a><a target="_top" href="http://java.sun.com/products/jfc/swingdoc-api/com/sun/java/swing/table/TableCellEditor.html"><img src="../../images/apiIcon.gif" width=20 height=20 border=0 alt="(in the API reference documentation)"></a> interface.
Then you set up the component as an editor
for a data type or column,
using the
<code>setDefaultEditor</code> or
<code>setCellEditor</code>
method, respectively.
<p>
Here is a picture of a dialog that
a serves, indirectly, as a cell editor.
When the user begins editing a cell in the Last Name column,
a button (the true cell editor) appears and
brings up the dialog,
through which the user chooses a last name.
<blockquote><IMG SRC="../../figures/ui/TableDialog.gif" WIDTH="280" HEIGHT="183" ALIGN="BOTTOM" NATURALSIZEFLAG="3" ALT="The cell editor brings up a dialog "></blockquote>
You can find the code in
<a href="example-swing/TableDialogEditDemo.java"><code>TableDialogEditDemo.java</code></a>
and
<a href="example-swing/TableDialog.java"><code>TableDialog.java</code></a>.
The example also requires
<a href="example-swing/WholeNumberField.java"><code>WholeNumberField.java</code></a>.
<p>
</blockquote>
<h4>
<a name="custom">
Further Customizing the Display and Event Handling
</a>
</h4>
<blockquote>
You've already seen how to specify cell <em>editors</em>.
You can also specify <em>renderers</em> for cells
and for column headers.
Customizing renderers lets you either
display data in custom ways
or add non-editing
functionality such as tool tips.
<p>
To add tool tips to a column's cells,
you need to get or create the column's default cell renderer,
and then use the <code>setToolTipText</code> method
of the renderer's component.
Here is the code in
<a href="example-swing/TableRenderDemo.java"><code>TableRenderDemo.java</code></a>
that adds tool tips
to both the cells and header for the Sport column:
<blockquote>
<pre>
//Set up tool tips for the sport cells.
DefaultTableCellRenderer renderer =
new DefaultTableCellRenderer();
renderer.setToolTipText("Click for combo box");
sportColumn.setCellRenderer(renderer);
//Set up tool tip for the sport column header.
TableCellRenderer headerRenderer = sportColumn.getHeaderRenderer();
if (headerRenderer instanceof DefaultTableCellRenderer) {
((DefaultTableCellRenderer)headerRenderer).setToolTipText(
"Click the sport to see a list of choices");
}
</pre>
</blockquote>
Here is the code that TableRenderDemo
uses to size its columns.
For each column,
the code gets the components used to render
that column's header and cells.
It then asks the components
how much space they need.
Finally, it uses the space information to set the column's width.
<blockquote>
<pre>
TableColumn column = null;
Component comp = null;
int headerWidth = 0;
int cellWidth = 0;
Object[] longValues = model.longValues;
for (int i = 0; i < 5; i++) {
column = table.getColumnModel().getColumn(i);
comp = column.getHeaderRenderer().
getTableCellRendererComponent(
null, column.getHeaderValue(),
false, false, 0, 0);
headerWidth = comp.getPreferredSize().width;
comp = table.getDefaultRenderer(model.getColumnClass(i)).
getTableCellRendererComponent(
table, longValues[i],
false, false, 0, i);
cellWidth = comp.getPreferredSize().width;
<em>...//debugging code not shown...</em>
column.setMinWidth(Math.max(headerWidth, cellWidth));
}
<em>...//In the model:</em>
public final Object[] longValues = {"Angela", "Andrews",
"Teaching high school",
new Integer(20), Boolean.TRUE};
</pre>
</blockquote>
</blockquote>
<h4>
<a name="sorting">
Sorting and Otherwise Manipulating Data
</a>
</h4>
<blockquote>
To perform data manipulation such as sorting,
you can use one or more specialized table models
(<em>data manipulators</em>),
in addition to the table model that provides the data
(the data model).
The data manipulators
should sit between the table
and the data model,
as the following picture shows:
<blockquote><IMG SRC="../../figures/ui/tablemodel.jpg" WIDTH="589" HEIGHT="187" ALIGN="BOTTOM" NATURALSIZEFLAG="3" ALT=""></blockquote>
You can use the <code>TableMap</code> and <code>TableSorter</code> classes
when implementing your data manipulator.
<a href="example-swing/TableMap.java"><code>TableMap</code></a>
implements <code>TableModel</code>
and serves as a superclass for data manipulators.
<a href="example-swing/TableSorter.java"><code>TableSorter</code></a>
is a <code>TableMap</code> subclass
that sorts the data provided by another table model.
You can either
change these classes,
using them as a basis for writing your own data manipulator,
or use the classes
as-is to provide sorting functionality.
<p>
To implement sorting
with <code>TableSort</code>,
you need just three lines of code.
The following listing
shows the differences between TableDemo
and its sorting cousin,
<a href="example-swing/TableSorterDemo.java">TableSorterDemo</a>.
<blockquote>
<pre>
<B>TableSorter sorter = new TableSorter(myModel); //ADDED THIS</b>
//JTable table = new JTable(myModel); //OLD
<b>JTable table = new JTable(sorter); //NEW</b>
<b>sorter.addMouseListenerToHeaderInTable(table); //ADDED THIS</b>
</pre>
</blockquote>
The <code>addMouseListenerToHeaderInTable</code> method
adds a mouse listener that detects clicks
over the column headers.
When the listener detects a click,
it sorts the rows based on the clicked column.
For example,
when you click "Last Name",
then the rows are reordered so that the row with "Andrews"
becomes the first row.
When you Shift-click a column header,
the rows are sorted in reverse order.
<blockquote><IMG SRC="../../figures/ui/TableSorterDemo.gif" WIDTH="528" HEIGHT="120" ALIGN="BOTTOM" NATURALSIZEFLAG="3" ALT=""></blockquote>
</blockquote>
<h4>
<a name="api">
The Table API
</a>
</h4>
<blockquote>
[PENDING: put API tables here]
</blockquote>
<h4>
<a name="eg">Examples that Use Tables</a>
</h4>
<blockquote>
This table lists examples that use <code>JTable</code>
and where those examples are described.
<p>
<table>
<tr>
<th align=left> Example
<th align=left> Where Described
<th align=left> Notes
<tr>
<td> <a href="example-swing/TableDemo.java"><code>TableDemo.java</code></a>
<td> This page
<td> A basic table with no model.
<tr>
<td colspan=3> [PENDING: LIST MORE...]
</table>
</blockquote>
</blockquote>
<p>
<hr size=4>
<p>
<table width="100%">
<tr>
<td align=left>
<a href="tabbedpane.html"><img src="../../images/PreviousArrow.gif" width=26 height=26 align=top border=0 alt="Previous | "></a><a
href="text.html"><img src="../../images/NextArrow.gif" width=26 height=26 align=top border=0 alt="Next | "></a><a
href="../../trailmap.html"><img src="../../images/WayUpArrow.gif" width=26 height=26 align=top border=0 alt="Trail Map | "></a><a
href="../index.html"><img src="../../images/uiHeader.gif" width=26 height=26 align=top border=0 alt="Creating a User Interface | "></a>
</td>
<td align=right>
<a href="index.html"><strong><em>Using the JFC/Swing Packages</em></strong></a>
</td>
</tr>
</table>
</body>
</html>
--------------890D83D4D05AB925FF0B2E98
Content-Type: text/x-vcard; charset=koi8-r;
name="keenonjava.vcf"
Content-Transfer-Encoding: 7bit
Content-Description: Card for Vladimir Olenin
Content-Disposition: attachment;
filename="keenonjava.vcf"
begin:vcard
n:Vladimir;Olenin
x-mozilla-html:FALSE
adr:version:2.1
version:2.1
email;internet:keenonjava@collegemail.com
note:Java programmer. Open for project development offers. See my home page at: http://www.geocities.com/SiliconValley/Heights/9815/
end:vcard
--------------890D83D4D05AB925FF0B2E98--
Technical Details
Message-ID:
<3617F416.1280D3F7@collegemail.com>Path:
arc1-ca.pugleaf.net!unknown!not-for-mailReferences:
<6v68tb$9ui7@forums.borland.com>Show Full Headers
Complete Article Headers
X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 111d45,bf2742f8dac80943 X-Google-Attributes: gid111d45,public From: Vladimir Olenin <keenonjava@collegemail.com> Subject: Re: Colunn Headers for Jtable Date: 1998/10/05 Message-ID: <3617F416.1280D3F7@collegemail.com> X-Deja-AN: 397710190 References: <6v68tb$9ui7@forums.borland.com> X-Accept-Language: en,ru Content-Type: multipart/mixed; boundary="------------890D83D4D05AB925FF0B2E98" Organization: Another Netscape Collabra Server User Mime-Version: 1.0 Newsgroups: borland.public.jbuilder.java.swing