Sun Java Solaris Communities My SDN Account Join SDN
 
Swing Introduction

Swing

 

Bookshelf Index


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]