by cszhao1980
JTable是Swing中最复杂的组件之一。在JTable周围,环绕着JTableHeader、TableModel、TableColumn、TableColumnModel、ListSelectionModel、TableRowSorter
等多个辅助类(接口),如下图所示。
理解这些类(接口)之间的关系就显得尤为重要。
JTableHeader用来管理JTable的Header对象,通过JTable. getTableHeader()方法可以直接访问到JTableHeader对象。
某种意义上,TableHeader与Table维持了一种松散的关系,即TableHeader仅作为列名字使用,而不是Table的内容。比如:
(1) 在JTable绘制自己时,就不绘制Header部分——JTableHeader本身是个组件,可以通过在容器内添加TableHeader自身来完成Header的绘制;
(2) JTable的Row数里是不包含Header行的。
JScrollPane组件对JTable进行了特殊的处理,它会自动获取JTable的TableHeader,并将该组件添加到Column Viewport中。
TableColumn是JTable的具体的某一列,通过它可以设置该列的一些属性,如首选宽度、最小、最大宽度
Header的CellRenderer,列的CellRenderer、CellEditor etc。
在TableColumn中,Header部分使用特殊字段来表示。如,headerValue、headerRenderer。
而且如果没有对该设置该列的headerRenderer时,该字段为Null。此时,选用JTableHeader. getDefaultRenderer()返回的Renderer进行绘制。
TableColumn还用来充当JTable与TableModel
之间的桥梁——protected属性modelIndex内记录的就是该列在TableColumnModel内的Index值——TableColumn有多个构造函数使用modelIndex作为参数,即该TableColumn即为TableColumnModel中的index为modelIndex的列。这段话听来来比较绕,难以理解。其实是这样的: 作为TableModel
的视图,JTable与其Model保持了非常松散的关系。比如,我们可以在视图中对各列重新排序,而此时,Model中的列根本不受影响。
【注】:使用“索引”技术,可以很方便的实现不影响Model的排序。如:swing.pdf中就给出了一个使用装饰者模式包装真实Model,以“行索引”实现行排序的功能,短短几十行代码,就完成了这项功能。
接口TableColumnModel不是某个具体的Column,而是对所有Column进行管理。它还管理了若干属性——所有的TableColumn(表格列)都应该遵守,如ColumnMargin(列边距)等。它常用的方法有:
(1) 监听器的添加、去除(TableColumnModelListener);
(2) 添加、删除、移动列;
(3) 列选取(选取 控制);
(4) 其他,如:
getColumnMargin()
getColumnIndexAtX(int xPosition)
返回位于该水平点 |
JTable与其TableModel间维持一种非常松散的联系——只要实现TabelModel接口的类都可以作为其模型。而JTable仅通过TabelModel接口定义的方法来访问模型数据——它根本不关心Model内部数据的具体存放方式。TableModel接口并不复杂:
void |
addTableModelListener(TableModelListener l) |
Class<?> |
getColumnClass(int columnIndex) |
int |
getColumnCount() |
String |
getColumnName(int columnIndex) |
int |
getRowCount() |
Object |
getValueAt(int rowIndex, int columnIndex) |
boolean |
isCellEditable(int rowIndex, int columnIndex) |
void |
removeTableModelListener(TableModelListener l) |
void |
setValueAt(Object aValue, int rowIndex, int columnIndex) |
大多数方法都比较好理解,如:
(1) getValueAt(row, column)——通过该方法,JTable获取每个Cell的值;
(2) getColumnName(row, column) —— JTable获取column name;
值得一提的是getColumnClass(column), 通过调用该方法,JTable可以获取每一列(存储内容class)的Class对象,来决定该Column的default Renderer。
Swing提供了默认的TableModel实现,供大家选用,如下图所示。
AbstractTableModel实现TableModel接口,此抽象类为 TableModel
接口中的大多数方法提供默认实现。它负责管理侦听器,并为生成TableModelEvents
以及将其调度到侦听器提供方便。要创建一个具体的 TableModel
作为 AbstractTableModel
的子类,只需提供对以下三个方法的实现:
public int getRowCount();
public int getColumnCount();
public Object getValueAt(int row, int column);
该抽象类:
(1) setValueAt()为空实现;
(2) getColumnClass()均返回Object Class对象。
这会使用EDIT作为defaultRenderer,显示的内容为Cell存放对象的toString的返回值。
DefaultTableModel扩展了AbstractTableModel抽象类,它使用Vector来存放模型数据,可以使用getDataVector()来获取该vector。
public Vector getDataVector() 返回由多个包含表数据值的 Vector 组成的 Vector。外层 vector 中包含的每个 vector 都是一行的值。换句话说,要获得第 1 行、第 5 列的单元格,可以使用以下代码: ((Vector)getDataVector().elementAt(1)).elementAt(5); |
同AbstractTableModel一样,getColumnClass()也返回Object Class对象,可以重载此方法,以返回更加准确的类型。
同JList一样,JTable也使用ListSelectionModel来管理其选取,共有三种选取模式(属性:SelectionModel):
static int |
MULTIPLE_INTERVAL_SELECTION |
static int |
SINGLE_INTERVAL_SELECTION |
static int |
SINGLE_SELECTION |
通过JTable..getSelectionModel()可以访问它的选取模型。
JTable还提供了以下方法,对选取进行控制:
(1) setColumnSelectionAllowed(boolean);
(2) setRowSelectionAllowed(boolean);
(3) setCellSelectionEnabled(boolean);