CHANGES TO THE TABLE API Feedback from users of JTable has helped us find several areas of the table API that cause problems. Unfortunately, addressing these problems will require some incompatible changes to the table API. These changes aren't in this release; we plan to put them in the following one. As an overview, our main concern for the JTable was that its responsibilities were starting to stray into the spreadsheet / data-repository space which is not what the JTable was intended to be. In the next release we will be using the API to draw a clear boundary around the JTable's essential functionality to ensure these related issues can be solved from outside the Swing codebase. By removing the need to find general solutions to these problems inside the JTable we will be able to focus on the efficiency and quality of the JTable as a UI component whose primary task is to provide an editable view of tabular data. Issues and Solutions -------------------- Here are some of the key issues and our planned solutions: Issues: Performance and scalability Solutions: - Replace the linear search for visible rows with a calculation based on the position of the Viewport - Remove all of the linear searches for column identifiers in the inner loops of the rendering code - Generally ensure that rendering and manipulation in the JTable is completely independent of the size of the model - Optimize performance for large tables with common data types Issues: General confusion due to inconsistencies in the way columns are identified throughout the API and a lack of clarity about the separation between a JTable and its DefaultTableModel Solutions: - Remove the requirement for each TableModel to deal with identifiers; identifiers will remain in some of the JTable API as an optional convenience for tagging and locating TableColumns - Remove all the conveniences in the JTable that work only with the DefaultTableModel Issues: Many requested enhancements and bug fixes for spreadsheet-like data manipulation inside the DefaultTableModel; rendering/layout problems Solutions: - Remove spreadsheet-like functionality from the DefaultTableModel - Use the API to draw a clear boundary around what the JTable is supposed to do, so that general data manipulation can be done from outside the JTable (and Swing APIs). This will allow us to focus exclusively on improving the efficiency and quality of the UI part of these architectures. Planned Changes --------------- 1. De-emphasize DefaultTableModel. The changes to the TableModel interface in 0.5 made the construction of a JTable with a custom TableModel fairly trivial, considerably reducing the usefulness of DefaultTableModel. Generally it is much better to wrap data in an application with the methods from the TableModel interface than to copy it into the DefaultTableModel. The copying of data is not a scalable technique and it often makes editing and dealing with external changes more difficult. Nevertheless, DefaultTableModel will not be dropped altogether because it is a general Swing policy to create default models when none are provided in a constructor. The DefaultTableModel will therefore be maintained in a reduced form, with its sorting behavior removed (it currently has a number of flaws). We don't recommend using DefaultTableModel for anything other than very simple applications dealing with restricted volumes of data. 2. Replace column identifiers with ints. The linear search in the DefaultTableColumnModel's getColumnIndex() method is a performance problem, taking 80% of rendering CPU in some (fairly pathological) cases and ~8% in "common" ones. The Column identifiers -- object references to columns -- will be deleted from all of the performance critical parts of the table package, to be supplanted by an integer that refers to the column's position. An exception will be the TableColumn which will retain the ability to store an identifier as an optional tag. The JTable will also retain its convenience methods to locate columns by their identifier. By default, the identifier will be set to the name of the column though the TableColumn's setIdentifier method can be used to set a different value which may be of any type. The JTable will correctly render all values from its model regardless of the type and uniqueness of these identifiers. 3. Make row and column arguments consistent. We'll probably do this by enforcing these rules: 1. When a method has both row and column arguments, the row argument will come first. 2. Object column arguments will be changed to ints. Details of Planned API Changes ------------------------------ REMOVE the following JTable methods (because they work only with DefaultTableModels): addColumn(Object, int, TableCellRender, TableCellEditor, Vector) addColumn(Object columnIdentifier, Vector columnData) addRow(Object[] rowData) addRow(Vector rowData) checkDefaultTableModel() insertRow(int rowIndex, Object[] rowData) insertRow(int rowIndex, Vector rowData) moveRow(int startIndex, int endIndex, int toIndex) removeColumn(Object columnIdentifier) removeRow(int rowIndex) setDataVector(Object[][] newData, Object[] columnIds) setDataVector(Vector newData, Vector columnIds) setNumRows(int newSize) REMOVE the following TableModel methods (because the table model doesn't require object identifiers any more): getColumnIdentifier(int columnIndex) getColumnIndex(Object columnIdentifier) REMOVE the following DefaultTableModel methods (because manipulation of data should not be part of a UI package): quicksort doCompare Make the row/column method arguments consistent: In TableModel: getValueAt(int rowIndex, int columnIndex) In JTable: getValueAt(Object columnIdentifier, int rowIndex) getValueAt(int columnIndex, int rowIndex) In all appropriate methods of the following classes: BasicTableHeaderUI DefaultTableColumnModel DefaultTableModel TableCellEditor TableCellRenderer TableColumn TableColumnModel TableModelEvent How to Prepare for the Coming Changes ------------------------------------- If possible, use the table API in the simple ways demonstrated in the SwingSet example (examples/SwingSet/TablePanel.java) and by the Table demos: TableExample1, TableExample2, TableExample3. Try to isolate any dependency on the other parts of the table package so that there will be only one place where you need to change your code. Here's an example of how getting columns will change. This example shows how to change TableExample4 (in example/Table), which currently uses getColumn((Integer)someInt). NOW: TableColumn column3 = tableView.getColumn(new Integer(3)); column3.setWidth(40); TableColumn column0 = tableView.getColumn(new Integer(0)); ... column0.setCellEditor(new DefaultCellEditor(textField)); FUTURE: TableColumn column3 = tableView.getColumn("Favorite Number"); column3.setWidth(40); TableColumn column0 = tableView.getColumn("First Name"); ... column0.setCellEditor(new DefaultCellEditor(textField));