|
Bookshelf Index
Chapter 18, Tables
By Matthew Robinson and Pavel Vorobiev
Introduction |
Download Chapter 18| Download Chapter 22 << NEXT >>
18.1.4 DefaultTableModel
class javax.swing.tableDefaultTableModel
DefaultTableModel is the default concrete
TableModel
implementation
used by JTable when
no model is specified in the constructor. It uses a
Vector of
Vectors to manage its data, which is one major
reason why extending AbstractTableModel
is often more desirable (because AbstractTableModel
allows
complete
control over how data
storage and manipulation is implemented). This
Vector can
be
assigned with the overloaded setDataVector() method,
and
retrieved with the getDataVector()
method. Internally, two overloaded, protected
convertToVector()
methods are used for converting Object arrays to
Vectors when inserting
rows, columns, or assigning a new data Vector.
Methods
for
adding,
inserting, removing,
and moving columns and rows of data are also provided.
Note: The
position of a row or column in the model does not correspond to
JTable's GUI representation of that row or
column. Rather, this representation is performed instances of
TableColumn which map to specific model
columns. When a TableColumn is moved
in the GUI, the associated data in the TableModel
model stays put, and vice versa (see below).
Along with the TableModelEvent
functionality inherited from AbstractTableModel,
this class implements three new event-dispatching methods, each
taking
a
TableModelEvent as
parameter: newDataAvailable(),
newRowsAdded(), and rowsRemoved(). The
newRowsAdded() method
ensures that new rows (see discussion of
TableModelEvent
below)
have the correct number of
columns by either removing excess elements, or using
null
for
each
missing cell. If null is passed to any of
these methods they will construct and fire a default
TableModelEvent which assumes that all table
model data has changed.
18.1.5 TableColumn
class javax.swing.table.TableColumn
TableColumn is the basic building block of
JTable's
visual
representation, and provides the main link between the
JTable GUI
and its model. Note that TableColumn does not extend
java.awt.Component,
and is thus not a component. Rather, it acts more like a model
that
maintains
all the properties of a column displayed in a
JTable. An
instance
of TableColumn represents a specific column of data
stored in a TableModel.
TableColumn maintains
the index of the TableModel
column it represents as property modelIndex. We can
get/set this
index with the getModelIndex() and
setModelIndex()
methods. It
is important to remember that the position of a
TableColumn
graphically in JTable does not at all correspond to
the
corresponding TableModel
column index.
A TableColumn is represented graphically by a column
header renderer, cell renderer, and optionally a cell editor. The
renderers
must be instances of TableCellRenderer,
and the editor must be an instance of TabeCellEditor
(see
below).
A
column's header is rendered by a
component stored as the headerRenderer
property. By default this is an instance of
DefaultTableCellRenderer (a JLabel with
a
beveled
border--see below) and
is created with TableColumn's
protected createDefaultHeaderRenderer()
method. This renderer simply renders the String
returned
by the
toString() method of the Object
referred to
by the
headerValue property. The
header renderer and value can be assigned/retrieved with
setHeaderRenderer()/getHeaderRenderer()
and
setHeaderValue()/getHeaderValue()
methods
respectively. Often headerValue
directly corresponds to the column name retrived using
TableModel's
getColumnName() method. If headerValue
is
not
explicitly set it
defaults to null.
The column cell renderer and editor
also default to null,
and unless they are explicitly specified using
setCellRenderer()
or
setCellEditor(), are automatically assigned based
on the Class type of
the data stored in the associated column in the
TableModel
(retreived using TableModel's
getColumnClass()
method). Explicity specified
renderers and editors are referred to as column-based,
whereas those determined by data type are referred to as
class-based
(we
will discuss renderers and editors in more detail
below).
Each TableColumn has an identifier
property
which
also
defaults null. This
property can be assigned/retrieved using typical set/get
accessors,
and the
getIdentifier() method will
return the headerValue
property if identifier
is null. When
searching for a TableColumn
by name (using TableColumnModel's
getColumnIndex()
method--see below--or JTable's
getColumn() method),
the given Object will
be compared, using Object's
equals() method, to
each TableColumn identifier. Since it
is
possible that more than one TableColumn
will use the same identifier,
the first match is returned as the answer.
TableColumn maintains properties
minWidth,
maxWidth, and width. The first two
specify the minimum and maiximum allowable widths for column
rendering, and
the
width property stores
the current width. Each can be retrieved and assigned with
typical
get/set
methods: getMinWidth()/setMinWidth(),
getMaxWith()/setMaxWidth(),
and getWidth()/setWidth().
minWidth defaults to 15,
maxWidth
defaults to Integer.MAX_VALUE, and
width
defaults to
75. When a JTable is resized it will
try to
maintain
its
width, and will never exceeed its maximum or shrink smaller than
its
minimum.
Note: All
other visual aspects of each column are controlled by either
JTable
or TableColumnModel
(see below).
TableColumn also maintains an
isResizable
property,
specifying
whether or not its width can be changed by the user (this does
not
apply to
programmatic calls to setWidth()).
(We will discuss resizing in more detail below).
An interesting and rarely used
property maintained by TableColumn,
resizedPostingDisabledCount,
is used to enable/disable the posting of
PropertyChangeEvents
when
a TableColumn's width changes. This is an
int value
that is
incremented on each call to disableResizedPosting(),
and
decremented on each call to enableResizedPosting().
Events will only be fired if this value is less than or equal to
0.
The logic
behind this is that if two separate sources both disable resize
event
posting,
then two calls should be required to re-enable it.
Bug Alert! As
of Java 2 FCS the resizedPostingDisabledCount
property is not actually used anywhere and does not play a role
in
PropertyChangeEvent firing.
TableColumn fires PropertyChangeEvents
when
any of
the
width, cellRenderer,
headerRenderer, or
headerValue bound
properties change. Thus we can add and remove
PropertyChangeListeners to be notified of these
changes. The corresponding property names are
COLUMN_WIDTH_PROPERTY,COLUMN_RENDERER_PROPERTY
,
HEADER_RENDERER_PROPERTY,and
HEADER_VALUE_PROPERTY.
18.1.6 The TableColumnModel Interface
abstract interface javax.swing.table.TableColumnModel
This model is designed to maintain a JTable's
TableColumns, and provides
control over column selections and margin size.
TableColumnModel
controls how JTable displays its
TableModel
data.
The
addColumn() method should
append a given TableColumn
to the end of the structure used to maintain them (usually a
Vector), removeColumn() should
remove a given TableColumn,
and moveColumn()
should change the location of a given TableColumn
within
that
structure.
Note: When
creating a JTable, if no
TableColumnModel is
specified, one will
automatically be constructed for us containing
TableColumns
displaying TableModel data in the same
order it appears in the model. This will only occur of
JTable's
autoCreateColumnsFromModel
property is set true, which it is by
default. This is very helpful, but has the often undesirable
side-effect of
completely rebuilding the TableColumnModel
whenever TableModel changes. Thus it
is common to set this property to false
once a JTable has been created or after
a new TableModel is assigned.
Unlike the location of a column in TableModel
implementations,
the index of a TableColumn
in a TableColumnModel's
storage structure directly corresponds to its position in the
JTable GUI. Note that the moveColumn()
method is
called whenever the user drags a column to a new position.
The getColumnCount() method should return the number
of
TableColumns
currently maintained, getColumns()
should return an Enumeration
of all contained TableColumns,
and getColumn()
returns the TableColumn
at the given index. The getColumnIndex()
method should return the index of the TableColumn
whose
identifier property is equal to (using
Object's
equals() method) the given Object.
getColumnIndexAtX() should return the index of the
TableColumn at the given
x-corrdinate in table-space (if getColumnIndexAtX()
is passed a coordinate that maps to the margin space between
adjacent
columns,
or any x-coordinate that does not correspond to a table column,
it
will return
-1). setColumnMargin()
and getColumnMargin()
should allow assignment and retrieval of an int
value for
use as
the margin space on each side
of each table column. The getTotalColumnWidth()
should return the sum of the current width of all
TableColumns
including all margin space.
Note: The
margin size does not correspond to the width of the separating
grid
lines
between columns in JTable. In fact,
the width of these lines is always 1, and cannot be
changed
without
customizing
JTable's UI delegate.
TableColumnModel declares methods for controlling
the selection of its TableColumns,
and allows assignment and retrieval of a
ListSelectionModel
implementation used to store
information about the current column selection with the methods
setSelectionModel() and
getSelectionModel().
The
setColumnSelectionAllowed()
method is intended to turn on/off column selection capabilities,
and
getColumnSelectionAllowed()
should return a boolean
specifying whether slection is currently allowed or not. For
convenience,
JTable's setColumnSelectionAllowed()
method delegates its traffic to the method of the same signature
in
this
interface.
TableColumnModel also declares support for
TableColumnModelListeners
(see below). TableColumnModel
implementations are expected to fire a
TableColumnModelEvent
whenever a TableColumn is added,
removed, or moved, a ChangeEvent
whenever margin size is changed, and a
ListSelectionEvent
whenever
a change in column
selection occurs.
18.1.7 DefaultTableColumnModel
class javax.swing.table.DefaultTableColumnModel
This class is the concrete default
implementation of the TableColumnModel
interface used by JTable
when none is specifically assigned or provided at construction
time.
All
TableColumnModel methods
are implemented as expected (see above), and the following
protected
methods
are provided to fire events: fireColumnAdded(),
fireColumnRemoved(), fireColumnMoved(),
fireColumnSelectionChanged(),
and fireColumnMarginChanged().
A valueChanged()
method is provided to listen for column selection changes and
fire a
ListSelectionEvent when necessary.
And a propertyChanged()
method is used to update the totalColumnWidth
property when the width
of a contained TableColumn
changes.
18.1.8 The TableCellRenderer interface
abstract interface
javax.swing.table.TableCellRenderer
This interface describes the renderer
used to display cell data in a TableColumn.
Each TableColumn has
an associated TableCellRender
which can be assigned/retrieved with the
setCellRenderer()/getCellRenderer()
methods.
The
getTableCellRendererComponent()
method is the only method declared by this interface, and is
expected
to
return
a Component that will
be used to actually render a cell. It takes the following
parameters:
JTable table:
the table instance containing the cell to be rendered.
Object value:
the value used to represent the data in the given cell.
boolean
isSelected: whether or not the given cell is selected.
boolean
hasFocus: whether or not the given cell has the focus
(true
if it was clicked
last).
int row:
can be used to return a renderer component specific to row or
cell.
int column:
can be used to return a renderer component specific to column or
cell.
We are expected to customize or vary
the returned component based on the given parameters. For
instance,
given a
value that is an instance
of Color, we might
return a special JLabel
subclass that paints a rectangle in the given color. This method
can
be used
to
return different renderer components on a column, row, or
cell-specific basis,
and is similar to JTree's
TreeCellRenderer
getTreeCellRendererComponent()
method. As with JTree
and JList, the
renderer component returned acts as a rubber stamp API used
strictly
for
display
purposes.
Note: the row and column
parameters refer to the location of data in the
TableModel,
not a cell location in the TableColumnModel.
When JTable's UI delegate repaints a certain region
of a
table it must query that table to determine the renderer to use
for
each cell
that it needs to repaint. This is accomplished through
JTable's
getCellRenderer() method which takes row and column
parameters, and returns the component returned by the
getTableCellRendererComponent() method of
the TableCellRenderer
assigned to the appropriate TableColumn.
If there is no specific renderer assigned to that
TableColumn
(recall that this is the case by default),
the TableModel's getColumnClass()
method is
used to recursively determine an appropriate renderer for the
given
data type.
If there is no specific class-based renderer specified for a
given
class,
getColumnClass() searches
for one corresponding to the super-class. This process will, in
the
most
generic case, stop at Object,
for which a DefaultTabelCellRenderer
is used (see below).
A DefaultTreeCellRenderer is also used if the class
is of type Number
(subclasses are BigDecimal, BigInteger,
Byte, Double, Float,
Integer, Long, and Short)
or
Icon. If the type happens
to be a Boolean, a JCheckBox is used.
We can
specify additional class-based renderers with
JTable's
setDefaultRenderer() method. Remember that
class-based
renderers will only be used if no column-based renderer has been
explicitly
assigned to the TableColumn
containing the given cell.
Page
1
2
3
4
5
6
7
8
9
10
11
<< NEXT >>
Download Chapter 18| Download Chapter 22]
|