Exploring Swing's Table Component
What is the most common way to organize many related values? Consider a table. A table organizes related values in a row-and-column format. Each row presents a collection of values that describes some entity (such as an employee), and each column imparts meaning to every row's value that appears in that column (such as a column of names, a column of addresses, and so forth). Tables are so pervasive in the computer science world that they form the basis of relational databases. A Java developer accesses a relational database (by using the JDBC API) to bring a database table's values into a Java program. Because it is beneficial to display those values to the program's users in a tabular format, Java developers often consider Swing's table component when they need to accomplish that task.
This article is the first in a trilogy of articles that explores Swing's table component. The first article walks you through a tutorial of most table component features and provides you with detailed behind-the-scenes information on how table component features work. The second and third articles expand on the first article by offering several tips for creating more powerful table components. Once you complete this trilogy of table component articles, you will possess a more complete understanding of Swing's table component and will be able to enhance that component to meet your needs.
NOTE
All programs that appear in these three articles have been tested with Version 1.4 of Sun's Java 2 Standard Edition SDK.
Introducing the Table Component
What is a table component? My definition is the combination of an object created from the JTable class and several objects created from other classes that are referenced from JTable field variables. Once the JTable object has been added to a container and the container has been made visible, a rendering of the table component appears on the screen. Figure 1 presents a GUI composed of a single table component.
Figure 1 Swing's table component displays as a crisscrossing grid of rows and columns. The intersection of a row and a column is known as a cell.
Figure 1 shows that a table component displays as a crisscrossing grid of rows and columns. Each of the white rectangles between grid lines, known as a cell, displays a value. As Figure 1 also shows, a table component is capable of displaying a header of column names. The header's column names, in Figure 1, are Name and Address.
To effectively use a table component, you need to become familiar with its architecture. One way to familiarize yourself with table component architecture is to know what classes and interfaces are involved in the creation and management of that component. Table 1 summarizes most of those classes and interfaces.
Table 1 Table Component Classes and Interfaces
Class/Interface |
Description |
javax.swing.AbstractCellEditor |
A convenience class that provides default implementations for most of the CellEditor interface's methods. |
javax.swing.CellEditor |
An interface that a class must implement if its objects are to edit cells in table components, tree components, or list components. |
javax.swing.DefaultCellEditor |
The standard class for editing table component cells or tree component cells. |
javax.swing.Jtable |
The main class. From JTable, a Swing table component is created. |
javax.swing.event.TableColumnModelEvent |
A class whose objects describe changes to the column models of table components. |
javax.swing.event.TableColumnModelListener |
A class that defines those methods that an object's class must implement if it is to listen for table component column model events. |
javax.swing.event.TableModelEvent |
A class whose objects describe changes to the models of table components. |
javax.swing.event.TableModelListener |
A class that defines those methods that an object's class must implement if it is to listen for table component model events. |
javax.swing.table.AbstractTableModel |
A convenience class that provides default implementations for most of the TableModel interface's methods. |
javax.swing.table.DefaultTableCellRenderer |
The standard class for rendering a table component's cells. |
javax.swing.table.DefaultTableColumnModel |
The standard class for managing a table component's columns. |
javax.swing.table.DefaultTableModel |
The standard class for managing a table component's model cell values. |
javax.swing.table.JtableHeader |
A class whose objects manage table component headers. |
javax.swing.table.TableCellEditor |
An interface that a class must implement if its objects are to edit table component cells. TableCellEditor extends CellEditor. |
javax.swing.table.TableCellRenderer |
An interface that a class must implement if its objects are to render table component cells. |
javax.swing.table.TableColumn |
A class whose objects describe the attributes (such as width, editor, and renderer) of individual table component columns. |
javax.swing.table.TableColumnModel |
An interface that a class must implement if its objects are to manage the columns of various table components. |
javax.swing.table.TableModel |
An interface that a class must implement if its objects are to manage the cell values of various table components. |
javax.swing.plaf.basic.BasicLookAndFeel |
The base class of all look-and-feel classes. Among other things, BasicLookAndFeel associates keystroke names with tasks that a table component must perform (such as initiating an editing session). |
javax.swing.plaf.basic.BasicTableHeaderUI |
The base class for look-and-feel classes that serve as UI delegates for JTableHeader components. |
javax.swing.plaf.basic.BasicTableUI |
The base class for look-and-feel classes that serve as UI delegates for JTable components. |
After reading Table 1, you might be wondering what the terms look and feel and UI delegates mean. The next section explores those terms. As you will discover, the concepts of look and feel and UI delegates are important to understanding the architecture of table components.
Delegating Look and Feel
A table component's architecture is based on another architecture known as the model-view-controller architectureMVC, for short. In the late 1970s, Xerox PARC developed the MVC architecture for use with its Smalltalk windowing system. That architecture splits a component into a model, one or more views, and a controller.
A component's state is maintained by a model. For example, button press information is maintained by a button model. A visual representation of that model's state is provided by a view. The view gives a component its look. For example, a button view draws a button so that it appears to be either pressed or not pressed, depending on the press information contained in the model. The controller determines whether a component can respond to input events that originate from input devices (such as keyboards and mice), and it gives a component its feel. For example, when you press a mouse button over some view of a button component, the button component's controller contacts the button component's model to have that model update itself. In turn, the model contacts the button component's view with a request for the view to redraw itself.
It is much easier to customize a component by changing its model, view, or controller than it is to change the entire component. To change a Swing component's model, either Swing (usually through a constructor) or your own code calls that component's setModel() method. For example, the JTable class declares a setModel(TableModel m) method that either you or one of JTable's constructors calls to establish a table component's model. The TableModel interface argument m references the object that will serve as that model. That object declares several methods for managing and communicating with the table component's model.
When a component's view and controller are changed, the component is said to adopt a new look and feel. For example, a button's view and controller can be changed to take on the look and feel of a Windows button, a Macintosh OS button, or a Unix Motif button. Because it is more common to change both a view and a controller than to change either entity separately, many windowing systems (including Swing) collapse a component's controller and view into a single entity, which is known as a UI (User Interface) delegate. UI delegates and models are completely separate, so a UI delegate can associate with more than one model, and a model can associate with more than one UI delegate. Typically, a UI delegate contacts a component's model when that model needs to change. In turn, the model can inform a program that a change has taken place. To change a Swing component's UI delegate, Swing calls that component's setUI() method. For example, to change a table component's UI delegate, Swing calls JTable's setUI(TableUI ui) method (which overrides JComponent's setUI(ComponentUI ui) method). The setUI(TableUI ui) method sets the UI delegate for a table component to the object referenced by TableUI class argument ui. That object declares several methods for managing a table component's look and feel, and communicates with the table component's model.
NOTE
Table 1 lists the BasicTableUI class. BasicTableUI subclasses the abstract TableUI class and serves as a basic UI delegate for table components. Other classes build on top of BasicTableUI to provide additional UI delegates for other looks and feels. The same idea holds for BasicTableHeaderUI.