Sun Java Solaris Communities My SDN Account Join SDN
 
Swing Introduction

Swing

 

Bookshelf Index


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]