|
Bookshelf Index
Chapter 18, Tables
By Matthew Robinson and Pavel Vorobiev
Introduction |
Download Chapter 18| Download Chapter 22 << NEXT >>
In this chapter:
JTable
Table: Part I - Basic JTable example
Table: Part II - Custom renderers
Table: Part III - Data formatting
Table: Part IV - Sorting columns
Table: Part V - JDBC
Table: Part VI - Column addition and removal
Expense Report Application
JavaBeans Property Editor
18.1 JTable
JTable is extremely useful for the display,
navigation, and editing of tabular data. Because of its complex
nature,
JTable has a whole package
devoted just to it: javax.swing.table.
This package consists of a set of classes and interfaces which we will
review
briefly here. In the examples that follow, we construct--in a
step-wise
fashion--a table-based application used to display stock market data.
(In
Chapters 22 and 26 we enhance this application further to allow
printing and
print preview, as well as CORBA client-server interaction.) This
chapter
concludes with an expense report application demonstrating the use of
different
components as table cell editors and renderers, and the completion of
the
JavaBeans property editor we
started to
build in Chapter 4.
18.1.1 JTable
class javax.swing.JTable
This class represents Swing's table
component and provides a rich API for managing its behavior and
appearance.
JTable directly extends JComponent and
implements
the TableModelListener,
TableColumnModelListener,
ListSelectionListener,
CellEditorListener,
and the Scrollable
interfaces (it is meant to be placed in a JScrollPane).
Each
JTable has three models: a TableModel,
TableColumnModel, and ListSelectionModel.
All table
data is stored in a TableModel, normally in a
2-dimensional structure such as a 2D array or a Vector of
Vectors. TableModel
implementations specify how this data is stored, as well as manage the
addition,
manipulation, and retrieval of this data. TableModel also
plays a
role in dictating whether
or not specific cells can be edited, as well as the data type of each
column
of
data. The location of data in a JTable's
TableModel does not
directly correspond to the location of that data as displayed by
JTable itself. This part is
controlled at the lowest level by TableColumnModel.
A TableColumnModel is designed to maintain instances
of TableColumn, each
of which represents a single column of TableModel data.
TableColumn is the class that is responsible for
managing the display of a column in the actual JTable
GUI. Each
TableColumn has an associated cell renderer, cell
editor, table header, and a cell renderer for the table header. When a
JTable is placed in a JScrollPane these
headers are
placed in the scroll pane's COLUMN_HEADER viewport and
can be dragged and resized to reorder and change the size of columns.
A
TableColumn's header
renderer is responsible for returning a component used to render the
column
header,
and the cell renderer is responsible for returning a component used to
render
each cell. As with JList
and JTree renderers,
these renderers also act as rubber stamps API and are not at all
interactive.
The component returned by the cell editor, however,
is completely interactive. Cell renderers are instances of
TableCellRenderer and cell
editors are instances of CellEditor.
If none are explicitly assigned, default versions will be used based
on the
Class type of the
corresponding TableModel
colmn data.
TableColumnModel's job is to manage all
TableColumns,
providing
control over order, column selections, and margin size. To support
several
different modes of selection, TableColumnModel
maintains a ListSelectionModel
which, as we learned in chapter 10, allows single, single-interval,
and
multiple-interval selections. JTable
takes this flexibility even further by providing functionality to
customize
any
row, column, and/or cell-specific selection schemes we can come up
with.
We can specify one of several
resizing policies which dictate how columns react when another column
is
resized, as well as whether or not grid lines between rows and/or
columns
should appear, margin sizes between rows and columns, selected and
unselected
cell foreground and background colors, the hieght of rows, and the
width of
each column on a column-by-column basis.
With tables come two new kinds of
events in Swing: TableModelEvent
and TableColumnModelEvent.
Regular Java events apply to JTable
as well. For instance, we can use MouseListeners to
process
double
mouse clicks. ChangeEvents and
ListSelectionEvents
are
also used for communication in TableColumnModel.
Note:
Although JTable implements several
listener interfaces, it does not provide any methods to register
listeners
other
than those inherited from JComponent.
To attach listeners for detecting any of the above events we must
first
retrieve the appropriate model.
A number of constructors are provided
for building a JTable
component. We can use the default constructor or pass the table's data
and
column names each as a separate Vector.
We can build an empty JTable
with a specified number of rows and columns. We can also pass table
data to
the
constructor as a two-dimensional array of data Objects
along with
an Object array of column names. Other constructors
allow creation of a JTable
with specific models. In all cases, if a specific model is not
assigned in the
constructor, JTable
will create default implementations with its protected
createDefaultColumnModel(),
createDefaultDataModel(),
and createDefaultSelectionModel()
methods. It will do the same for each TableColumn
renderer and
editor, as well as its JTableHeader,
using createDefaultEditors(),
createDefaultRenderers(),
and createDefaultTableHeader().
JTable is one of the most complex Swing components
and keeping track of its constituents and how they interact is
intially a
challenge. Before we begin the step-wise construction of our stocks
table
application, we must make our way through all of these details. The
remainder
of this section is devoted to a discussion of the classes and
interfaces that
underly JTable.
18.1.2 The TableModel Interface
abstract interface
javax.swing.table.TableModel
Instances of TableModel are responsible for storing a
table's data in a 2-dimensional structure such as a 2-dimensional
array or a
vector of vectors. A set of methods is declared for use in retrieving
data
from
a table's cells. The getValueAt()
method should retrieve data from a given row and column index as an
Object, and setValueAt() should assign
the provided data object to the specified location (if valid).
getColumnClass() should
return the Class
describing the data objects stored in the specified column (used to
assign a
default renderer and editor for that column), and
getColumnName()
should return the String name associated with
the specified column (often used for that column's header). The
getColumnCount() and getRowCount() methods
should return the number of contained columns and rows
respectively.
Note: The getRowCount() is called frequently by
JTable for display purposes and should be
designed with efficiency in mind because of this.
The isCellEditable() method should return
true if
the
cell at the
given row and column index can be edited. The
setValueAt() method
should be designed so that if isCellEditable() returns
false, the object at the
given location will not be updated.
This model supports the attachment of
TableModelListeners
(see below) which should be notified about changes to this model's
data. As
expected, methods for adding and removing these listeners are
provided,
addTableModelListener() and
removeTableModelListener(),
and implementations are responsible for dispatching
TableModelEvents to those registered.
Each JTable uses one TableModel instance
which can
be
assigned/retrieved using JTable's
setModel() and getModel() methods
respectively.
18.1.3 AbstractTableModel
abstract class javax.swing.table.AbstractTableModel
AbstractTableModel is an abstract class
implementing the TableModel
interface. It provides default code for firing
TableModelEvents
with the fireTableRowsDeleted(),
fireTableCellUpdated(), and
fireTableChanged()
methods. It also manages all registered
TableModelListeners in an
EventListenerList (see chapter 2).
The findColumn() method searches for the index of a
column with the given String
name. This search is performed in a linear fashion (referred to as
naive in
the documentation) and should be overriden for large table models for
more
efficient searching.
Three methods need to be implemented
in concrete sub-classes: getRowCount(),
getColumnCount() and getValueAt(int row, int
column),
and we are expected to use this class as a base for building our own
TableModel implementations
(rather than DefaultTableModel--see
below).
Page
1
2
3
4
5
6
7
8
9
10
11
<< NEXT >>
Download Chapter 18| Download Chapter 22]
|