The Table Model
At the center of the complexity inherent in the JTable is the table model. Because the JTable is designed around the concepts of MVC (Model/View/Control), the table model controls how the data is stored. The table model is also usually misused due to the existence of the DefaultTableModel object. It is quite common for programmers to use the DefaultTableModel because it is easy or simple. Therein lies the trap: Once you start using the DefaultTableModel, you discover that it is not really meant for production use and does not lend itself to data manipulation at all.
So how can you avoid this trap? You can implement your own table model that is designed specifically for the purpose that you need. Fortunately, Sun has anticipated the need to write our own table model and has actually done some of the dirty work for us. Enter the AbstractTableModel, which implements the interface TableModel and handles your listeners for you. As seen below, the methods needed to implement from the AbstractTableModel are relatively few.
import javax.swing.table.AbstractTableModel; public class MyTableModel extends AbstractTableModel { public int getRowCount() { return 0; } public int getColumnCount() { return 0; } public Object getValueAt(int row, int col) { return null; } }
This represents the bare minimum that you need to implement. And surprisingly, by implementing these three methods, you can build a very robust TableModel that gives complete control over the data that it references. First, you must define where the data will be stored. Personally, I like to use a java.util.ArrayList for my data storage. After adding the array list to the table model, you can start to implement the methods.
public class MyTableModel extends AbstractTableModel { private ArrayList datalist = new ArrayList(); public int getRowCount() { return datalist.size(); }
Because each row in the table will be a single widget, the row count is merely the size of the array list. YOu initialize the array list immediately upon construction to avoid any chance of a NullPointerException.
The next method to implement is the ColumnCount. Because you know exactly what you want to display, you can hard-code this method for now. You will make this a little more flexible.
public int getColumnCount() { return 4; }
The final method that is required to implement is getValueAt. Of the three, this is the most complex method. First let me show you its implementation; then you can walk through it.
public Object getValueAt(int row, int col) { Widget widget = (Widget) datalist.get(row); switch (col) { case 0: return widget.getName(); case 1: return String.valueOf(widget.getValue()); case 2: return widget.getLocation(); case 3: return String.valueOf(widget.getQuantity()); default: return null; } }
The first thing is to get the widget that is being requested. Because each widget is its own row, you use the passed in parameter 'row' as the index against the datalist. You cast this into a Widget reference for easier manipulation. Next, switch off of the col index. Because you know what data will be displayed in what column (in fact, this method controls that), you simply return the values based on the index of the col parameter. Add a default return at the bottom of our switch statement to satisfy the Java compiler. And that's it!
You now have a basic and functional table model and can now display the Widgets in a JTable with no additional code. However, at this point, you are not doing anything above and beyond what a DefaultTableModel does. In fact, you are doing even less because the column names are not displayed.