I l@ve RuBoard |
![]() ![]() |
15.1 The JTable ClassBefore we get ahead of ourselves, let's look at the JTable class and its supporting cast members. 15.1.1 Table ColumnsWith Swing tables, the basic unit is not an individual cell but a column. Most columns in real-world tables represent a certain type of information that is consistent for all records. For example, a record containing a person's name is a String and might be the first column of the table. For every other record (row), the first cell is always a String. The columns do not need to all have the same data type. The same record could hold not only a person's name, but whether or not they owned a computer. That column would hold Boolean values, not String values. The models supporting JTable reflect this view of the world. There is a TableModel that handles the contents of each cell in the table. You will also find a TableColumnModel that tracks the state of the columns in the table (how many columns, the total width, whether or not you can select columns, etc.). The ability to store different types of data also affects how the table draws the data. The table column that maps to the "owns a computer" field could use a JCheckBox object for the cells of this column while using regular JLabel objects for the cells of other columns. But again, each column has one data type and one class responsible for drawing it. Now, as the JTable class evolves, you may find alternate ways to think about tables without relying so heavily on columns. You'll want to keep an eye on the API in future releases of the Swing package. Figure 15-2 shows how the classes of the JTable package fit together. Figure 15-2. JTable class diagram![]() Well, we made it this far without officially discussing the JTable class itself. Dynamic data and database queries are handled entirely by the table model underneath the display. So what can you do with a JTable object? The JTable class gives you control over the appearance and behavior of the table. You can control the spacing of columns, their resizability, their colors, and so on. The JTable object is the source of row selections. Through delegation, you can add and remove rows and columns directly with the JTable object. 15.1.2 PropertiesThe appearance of a JTable is manipulated almost entirely through its properties. To make things a bit more manageable, we'll break the properties up into three smaller tables: one for row, column, and cell properties; one for selection properties; and one for visual properties. Table 15-1 covers the row, column, and cell properties.
The autoCreateColumnsFromModel property determines whether the column model is loaded automatically with data from the table model. This value is set to true if you don't supply a non-null ColumnModel to the constructor. (You can always replace an existing column model with the setColumnModel( ) method.) The autoResizeMode property determines how the table reacts to being resized. Using the constants presented in Table 15-4, you can adjust all of the columns, only the last column, or shut resizing off altogether. You must turn off autoresizing if you want to use the horizontal scrollbar in your scroll pane. The columnCount and rowCount properties allow you to ask the JTable object how many rows and columns it has. These values come from the models in place. The columnModel property holds the current column model and can be replaced at runtime, if necessary. The rowHeight property dictates how tall rows are, in pixels. This property must be a number greater than or equal to one. Other values cause the setRowHeight( ) method to throw an IllegalArgumentException. The value of rowHeight includes the vertical intercell spacing. Table 15-2 lists the selection-related properties of the JTable class. The selectionModel property holds the ListSelectionModel object that handles row selections, and the selectionMode property applies to that model. (You can control the column selections with the selectionModel property of the TableColumnModel for your table.) The cellSelectionEnabled , columnSelectionAllowed, and rowSelectionAllowed properties determine whether you can select cells, columns, or rows. If cells are selectable, only cells can be selected, regardless of the row and column properties. With cell selection turned on and row and column selection turned off, you can still select a range of cells. With an active selection on your table, the selectedColumn , selectedColumnCount, selectedColumns, selectedRow, selectedRowCount, and selectedRows give you access to the various parts of that selection. The selectedRow and selectedColumn properties store the anchor selection (i.e., the first selection) from their respective selection models.
Table 15-3 covers the remaining properties of the JTable class. The cellEditor property determines the cell editor currently in use. When you start editing, the JTable class looks up your column and asks it for an editor. If the column has one, that editor is used; otherwise, a default editor for the column's class type is used. If no cell is currently being edited, this property is null. If you want your table to support automatic drag initiation, set the dragEnabled property to true. The gridColor , selectionBackground, and selectionForeground properties determine the color used for the grid lines and selection text. The intercellSpacing property determines the horizontal and vertical spacing around each cell in the table. The preferredScrollableViewportSize property determines the preferred size of the scrollpane for the table. The scrollableTracksViewportHeight and scrollableTracksViewportWidth properties are always false, which indicates that making the viewport around the table should not resize the table to fit the viewport (assuming you have placed the table in a scrollpane). You can control which lines show up on the table with showGrid , showHorizontalLines, and showVerticalLines. Use setShowGrid( ) as a convenient way to turn both horizontal and vertical lines on or off at the same time. The tableHeader property is used to store a JTableHeader object for your table. This header can be used in a JScrollPane as the column header for your table. (No row header counterpart is provided, but you can see an example of creating one in the next chapter.) The rowMargin property determines the amount of empty space between rows. This is really just a more convenient way of getting at the height information in the intercellSpacing property.
15.1.2.1 ExamplesTo see some of the more interesting properties in action, the following example sets up a simple (contrived) data set. We shut off autoresizing so that horizontal scrolling works properly. We also set the selection mode so that any range of cells can be selected. (We'll look at responding to selection events in the next section.) Figure 15-3. A simple JTable in a JScrollPane with a range of cells selected![]() Here's the source code that built the table in Figure 15-3: // TableFeature.java // A test of the JTable class using default table models and a convenience // constructor // import java.awt.*; import javax.swing.*; import java.util.Date; import java.io.File; public class TableFeature extends JFrame { String titles[] = new String[] { "Directory?", "File Name", "Read?", "Write?", "Size", "Last Modified" }; public TableFeature( ) { super("Simple JTable Test"); setSize(300, 200); setDefaultCloseOperation(EXIT_ON_CLOSE); File pwd = new File("."); Object[][] stats = getFileStats(pwd); JTable jt = new JTable(stats, titles); jt.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); jt.setColumnSelectionAllowed(true); JScrollPane jsp = new JScrollPane(jt); getContentPane( ).add(jsp, BorderLayout.CENTER); } public Object[][] getFileStats(File dir) { String files[] = dir.list( ); Object[][] results = new Object[files.length][titles.length]; for (int i=0; i < files.length; i++) { File tmp = new File(files[i]); results[i][0] = new Boolean(tmp.isDirectory( )); results[i][1] = tmp.getName( ); results[i][2] = new Boolean(tmp.canRead( )); results[i][3] = new Boolean(tmp.canWrite( )); results[i][4] = new Long(tmp.length( )); results[i][5] = new Date(tmp.lastModified( )); } return results; } public static void main(String args[]) { TableFeature tf = new TableFeature( ); tf.setVisible(true); } } 15.1.3 EventsAll table-specific events you would expect to see from the JTable class are routed through its data and column models. You must get a reference to these models and attach listeners to the models directly, with code like this example, which uses our custom EEL utility discussed in Chapter 3: TableModel myModel = new MyTableModel( ); // Some valid TableModel class JTable table = new JTable(myModel); EEL eel = EEL.getInstance( ); eel.addGui( ); // Listen for added/removed/updated rows. myModel.addTableModelListener(eel); TableColumnModel columnModel = table.getColumnModel( ); // Listen for added/removed/moved columns. columnModel.addTableColumnModelListener(eel); // Listen for row selections. myTable.getSelectionModel( ).addListSelectionListener(eel); // Listen for column selections. columnModel.getSelectionModel.addListSelectionListener(eel); You can see a more detailed example using the selection listeners later in this chapter. Examples using model listeners appear in Chapter 16. 15.1.4 ConstantsTable 15-4 shows the constants defined in JTable. These constants specify how columns behave when you resize the entire table or adjust a single column; they are used for the autoResizeMode property.
15.1.5 Constructors
15.1.6 Other Interesting MethodsHere are a few other methods to remember. These methods allow you to control tables programmatically. If you have other buttons or keyboard shortcuts for things like selecting matching records, these methods come in handy.
15.1.7 The TableColumn ClassThe TableColumn class is the starting point for building your columns. It supplies access to all the basic components of an individual column. This class should not be confused with the TableColumnModel interface. That model, discussed in the next section, dictates the form of a collection of table columns, which then makes up a full table. 15.1.7.1 PropertiesThe TableColumn class has the properties listed in Table 15-5.
The cellEditor , cellRenderer, and headerRenderer properties determine which components are used to draw (and possibly edit) cell values. The default value of null for these properties indicates that a default renderer or editor should be built and used. The headerValue property is accessible to the headerRenderer for drawing an appropriate header. The identifier property is used to identify a column uniquely. If an identifier is not specified, the getIdentifier( ) method returns the current headerValue. The minWidth and maxWidth properties determine the minimum and maximum width in pixels for the column. By setting these properties to the same value, you can create a fixed-width column. The current width of the column is stored in the width property. The modelIndex determines the index value used when rendering or editing the column to get the appropriate data values. It is normally set in the constructor and does not need to be modified after that. Relocating the column onscreen has no effect on the model index. The resizable property affects only the user's ability to manually resize columns—you can programmatically resize a column at any time. 15.1.7.2 ConstantsFour of the properties have descriptive constants that are used with property change events. These constants are listed in Table 15-6.
15.1.7.3 EventThe only event generated by the TableColumn class is a property change event that is generated when any of the column's bound properties (cellRenderer, headerRenderer, headerValue, and width) are changed.
15.1.7.4 ConstructorsThe following constructors exist for building TableColumn objects:
15.1.7.5 Another useful methodWhile the get/set methods for the properties constitute a majority of the TableColumn class, the following method does provide a bit of functionality:
15.1.8 The TableColumnModel InterfaceA single column is not a very interesting table—an interesting list, maybe, but not a table. To handle real tables (even ones with only one column), we need a model for storing several columns as a collection. The TableColumnModel interface provides that functionality in the Swing package. As you may have noticed from Figure 15-2, the JTable class has a column model in addition to a table model. While the table model provides the specific values for the cells in a column, the column model provides information such as the column margins and whether or not column selections are allowed. The TableColumnModel interface manages column selections and column spacing. For managing selections, you have access to the usual selection properties, such as the number of selected columns and the selection model in place. For dealing with column spacing, you can control the column margins and view the total column width. 15.1.8.1 PropertiesTableColumnModel has the properties listed in Table 15-7. The columnCount property returns the number of columns supported by this model. While this might seem like redundant information, given that the table model (discussed later in this chapter) knows how many columns it supports, the next chapter examines some column models that do not use all of the columns available in the table model. The columnMargin property dictates how much space should be left between columns. That spacing is included when calculating the value of the totalColumnWidth. You can turn column selection on or off with the columnSelectionAllowed property. If column selections are allowed, you can then use the selectionModel , selectedColumns, and selectedColumnCount properties to work with the selections. As with other selections, you can use the selectionModel to programmatically affect the selected columns if needed.
The column and columns properties let you access the table's columns themselves. The index used as an argument to getColumn( ) refers to the column's index in the column model, which doesn't necessarily match the index of the column in the table model, or the order in which columns appear on the screen. 15.1.8.2 EventAny class implementing the TableColumnModel interface has to support the ColumnModelEvent, which is generated when a column's view size, position, or extent size changes. The interface defines the standard addColumnModelListener( ) and removeColumnModelListener( ) methods, but the implementing class is responsible for the code that fires the events when columns are added, removed, or moved.
15.1.8.3 Column methodsThe TableColumnModel interface defines several methods for working with the columns in the model:
15.1.9 The DefaultTableColumnModel ClassThe DefaultTableColumnModel class implements the TableColumnModel interface and serves as the column model if you do not specify a model in the JTable constructor. It also works as a good starting point for creating your own column models. You inherit everything you need; just override the methods you want to change. 15.1.9.1 PropertiesThe DefaultTableColumnModel class inherits all of its properties from the TableColumnModel interface and supplies the default values shown in Table 15-8.
15.1.9.2 EventsThe DefaultTableColumnModel supports the ColumnModelEvent events that are dictated by the TableColumnModel interface, but it includes several convenience methods beyond simply attaching listeners:
15.1.9.3 Constructor
15.1.9.4 Other useful methods
15.1.10 The TableColumnModelEvent ClassMany of the events fired by the DefaultTableColumnModel class use this event class to encode the columns that were affected. Notice that these events describe something happening to a contiguous group of columns, unlike the selection events. There is no direct support for things like removing a discontiguous selection of columns. You must generate a different event for each contiguous range of columns that needs to be removed. 15.1.10.1 Event methods
15.1.11 The TableColumnModelListener InterfaceIf you want to listen to any of the column model events, you must implement the TableColumnModelListener interface and register as a listener for these events. Not surprisingly, the event-firing methods from the DefaultTableColumnModel class reflect the types of events this interface defines:
![]() |
I l@ve RuBoard |
![]() ![]() |