18.1.1 JTable
class javax.swing.JTable
上面这个类就代表了Swing的table组件,而且这个类提供了丰富的API来管理table的行为和table的表现形式。JTable直接继承自JComponent。JTable实现了5个接口,它们是:TableModelListener, TableColumnModelListener, ListSelectionListener, CellEditorListener以及Scrollable(实现Scrollable意味着table可以被放入JScrollPane中(It is meant to be pleaced in a JScrollPane))。每个JTable都有3个model,即:TableModel, TableColumnModel, ListSelectionModel。所有的table的数据都被放置在TableModel中,TableModel一般都是一个二维的结构,例如可能是个二维数组,或者是一个 元素是Vector的Vector。同时TableModel的实现还必须指定,这个model中的数据是如何存储的,而且还必须定义如何增加、操作、以及得到这个model的数据的方法。同时,TableModel在指定每个单元格是否可以被编辑,以及表的每列的数据的类型方面同样起着至关重要的作用。数据在TableModel中的位置和数据在JTable中显示的位置并不是直接对应的。实际上数据在TableModel中的位置和数据在JTable中显示的位置,之间的对应关系是通过最下层的TableColumnModel来控制的。
TableColumnModel是用来管理TableColumn的实例的,每个TableColumn代表的是TableModel的数据中的一个单独列。而TableColumn类则用来负责管理每个具体列在JTable GUI中的实际显示。每个TableColumn都有一个与之相关联的cell renderer, cell editor, table header以及table header的cell renderer。当一个JTable被放入了JScrollPane后,这些table header就被放在了scroll pane的COLUMN_HEADER viewport中,这些table header 可以被拖拽还可以被改变大小,从而我们也就可以对JTable的列重新排序和改变每列的宽度。一个TableColumn的 table header renderer返回一个用来render此列的table header的组件,而TableColumn的cell renderer负责返回一个用来render每个cell的组件。就像JList和JTree的renderer,这些renderer都像是邮戳,它们是不可以交互的。而由cell editor返回的组件则是完全可以交互的。cell renderer是TableCellRenderer的实例,cell editor是TableCellEditor的实例。如果没有显式的指派cell renderer和cell editor,那么根据TableModel的相应的每个列的数据的类型,每个列都会得到默认的cell renderer和cell editor。
TableColumnModel是用来管理所有的TableColumn之用的,TableColumnModel提供对列的显示顺序,列的选择以及margin size的控制。为了可以支持不同的选择模式,TableColumnModel也维护了一个ListSelectionModel,就像我们在第10章学习的那样,ListSelectionModel允许single,single-interval, multiple-interval selection。而JTable比这更加富有弹性,JTable甚至还提供给我们来自定义对某个行、列甚至单元格的选择。后面我们会学习这个。
我们可以指定一种resizing策略,这种策略用来指定,当我们resize一个列时,其他的列是如何动作的,我们还可以指定列之间或者行之间的割线是不是显示。我们还可以指定列之间、行之间的margin size,选中的未选中的格子的前景背景色,行的高度,以及每个列的宽度。
和talbe一起来的有两种事件,它们是TableModelEvent和TableColumnModelEvent,当然其他的java事件对JTable也是同样适用的。比方说,我们可以用MouseListeners来处理鼠标双击事件。ChangeEvents和ListSelectionEvents事件同样也可以用来和TableColumnModel进行交互。
Note:尽管JTable实现了几个监听器接口,但是JTable除了继承自JComponent的用来注册监听器的方法外,并没有提供任何其他的用来注册监听器的方法。如果想给JTable加上任何监听器以用来捕获上述事件,我们必须首先得到适当的model。
JTable有好几个构造函数。我们可以用默认的构造函数或者使用带有参数的构造函数,给JTable传递两个Vector分别用来盛放table的数据和table的列名。我们也可以指定行和列的个数来创建一个空的table。我们也可以用一个存放table数据的二维数组和一个存放列的名字的数组来传递给table的构造函数来构造一个table。其他的构造函数则允许我们利用指定的model来建立JTable。对于所有的构造函数来说,下面的事情都是成立的,也就是说,如果我们没有在构造函数中给table指派model,那么JTable将会用JTable的protected方法createDefaultColumnModel(),createDefaultDataModel()和createDefaultSelectionModel()来创建默认的实现。而且对每个TableColumn来说TableColumn的renderer,editor以及TableColumn的JTableHeader如果没有指定model那么也会用createDefaultEditors(),createDefaultRenderers()和createDefaultTableHeader()来创建默认的实现。
JTable是最复杂的Swing组件之一,追逐JTable的具体实现以及JTable的互动性质确实是个极大的挑战。在开始我们一步步的构造我们的股票表格程序之前,我们先打理通这些细节。这一节的剩余部分我们将会讨论决定JTable的内部机制的这些类和接口
总结:
TableModel的作用
1、 决定某个单元格是否可以编辑
2、 决定每一列的数据的类型
3、 实际存储JTable中的数据
4、 定义如何对JTable中的数据进行操作的方法
TableColumnModel的作用
1、 管理着所有的TableColumn的实例
2、 控制着列在JTable GUI上的显示顺序;JTable是如何被选择的,而且为了控制JTable的选择它还维护了一个ListSelectionModel;margin size
TableColumn的作用
1、 代表了TableModel中的数据的一个单独列
2、 就是数据在JTable GUI上实际的数据显示
3、 每个TableColumn都有四个东西cell renderer, table header renderer, cell editor和一个talbe header。而每个列之所以可以改变宽度以及可以改变显示的位置就是由于我们可以操纵这个这个TableColumn的table header