🍂JTable、TableModel实现表格
2021-3-22
| 2023-8-3
0  |  阅读时长 0 分钟
type
status
date
slug
summary
tags
category
icon
password
Property
 
 
表格也是GUI程序中常用的组件,表格是一个由多行、多列组成的二维显示区 。 Swing 的 JTable 以及相关类提供了这种表格支持 , 通过使用 JTable 以及相关类,程序既可以使用简单的代码创建出表格来显示二维数据,也可以开发出功能丰富的表格,还可以为表格定制各种显示外观、编辑特性 。
 

创建简单表格

使用JTable创建简单表格步骤:
  1. 创建一个一维数组,存储表格中每一列的标题
  1. 创建一个二维数组,存储表格中每一行数据,其中二维数组内部的每个一维数组,代表表格中的一行数据
  1. 根据第一步和第二步创建的一维数组和二维数组,创建JTable对象
  1. 把JTable添加到其他容器中显示
notion image
在上面实现的简单表格中,大概有如下几个功能:
  1. 当表格高度不足以显示所有的数据行时,该表格会自动显示滚动条 。
  1. 把鼠标移动到两列之间的分界符时,鼠标形状会变成可调整大小的形状,表明用户可以自由调整表格列的大小 。
  1. 在表格列上按下鼠标并拖动时,可以将表格的整列拖动到其他位置 。
  1. 当单击某一个单元格时,系统会自动选中该单元格所在的行 。
  1. 当双击某一个单元格时,系统会自动进入该单元格的修改状态 。
 
JTable调整列:
JTable提供了一个setAutoResizeMode(int mode)方法用来调整表格的格式,该方法可以接收下面几个值:
  1. JTable.AUTO_RESIZE_OFF: 关闭表格的自动调整功能。当调整某一列的宽度时,其他列的宽度不会发生变化;
  1. JTable.AUTO_RESIZE_NEXT_COLUMN:只调整下一列的宽度,其他列及表格的宽度不会发生改变;
  1. JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS:平均调整当前列后面所有列的宽度,当前列的前面所有列及表格的宽度都不会发生变化,这是默认的调整方式
  1. JTable.AUTO_RESIZE_LAST_COLUMN:只调整最后一列的宽度,其他列及表格的宽度不会发生变化;
  1. JTable.AUTO_RESIZE_ALL_COLUMNS:平均调整表格中所有列的宽度,表格的宽度不会发生改变
如果需要精确控制每一列的宽度,则可通过 TableColumn 对象来实现 。 JTable 使用 TableColumn 来表示表格中的每一列, JTable 中表格列的所有属性,如最佳宽度、是否可调整宽度、最小和最大宽度等都保存在该 TableColumn 中 。 此外, TableColumn 还允许为该列指定特定的单元格绘制器和单元格编辑器(这些内容将在后面讲解) 。 TableColumn 具有如下方法 。
  1. setMaxWidth(int maxWidth): 设置该列的最大宽度 。 如果指定的 maxWidth 小于该列的最小宽度, 则 maxWidth 被设置成最小宽度 。
  1. setMinWidth(int minWidth): 设置该列的最小宽度 。
  1. setPreferredWidth(int preferredWidth): 设置该列的最佳宽度 。
  1. setResizable(boolean isResizable): 设置是否可以调整该列的 宽度 。
  1. sizeWidthToFit(): 调整该列的宽度,以适合其标题单元格的 宽度 。
JTable调整选择模式:
  1. 选则行:JTable默认的选择方式就是选择行,也可以调用setRowSelectionAllowed(boolean rowSelectionAllowed)来修改;
  1. 选择列:调用 setColumnSelectionAllowed(boolean columnSelectionAllowed)方法,修改当前JTable的选择模式为列;
  1. 选择单元格:setCellSelectionEnabled(boolean cellSelectionEnabled) ,修改当前JTable的选择模式为单元格;
JTable调整表格选择状态:
与 JList 、 JTree 类似的是, JTable 使用了 一个 ListSelectionModel 表示该表格的选择状态,程序可以 通过 ListSelectionModel 来控制 JTable 的选择模式 。 JTable 的选择模式有如下三种:
  1. ListSelectionMode.MULTIPLE_INTERVAL_SELECTION:没有任何限制,可以选择表格中任何表格单元,这是默认的选择模式 。 通过 Shi负和 Ctrl 辅助键的帮助可以选择多个表格单元 。
  1. ListSelectionMode.SINGLE_INTERVAL_SELECTION:选择单个连续区域,该选项可以选择多个表格单元,但多个表格单元之间必须是连续的 。 通过 Shift 辅助键的帮助来选择连续区域。
  1. ListSelectionMode.SINGLE_SELECTION:只能选择单个表格单元 。
 
notion image
 
 

TableModel和监听器

与 JList、 JTree 类似的是 , JTable 采用了 TableModel 来保存表格中的所有状态数据 : 与 ListModel类似的是, TableModel 也不强制保存该表格显示的数据 。 虽然在前面程序中看到的是直接利用 一个二维数组来创建 JTable 对象,但也可以通过 TableModel 对象来创建表格。
使用TableModel步骤:
  1. 自定义类,继承AbstractTableModel抽象类,重写下面几个方法:
    1. 创建自定义类对象,根据该对象,创建JTable对象
     
     
    1. 连接数据库,把库中所有的表名称显示到下拉列表中
    1. 点击下拉列表中某个表名时,查询数据库该表的数据,并把结果封装到TableModel中,使用JTable展示
    1. 点击表格中某个单元格,修改数据,能实时修改数据库中的数据
    1. 每修改一次数据,把修改的信息打印到下方的文本域中
    notion image
    不仅用户可以扩展 AbstractTableModel 抽象类, Swing 本身也为 AbstractTableModel 提供了 一个DefaultTableModel 实现类,程序可以通过使用 DefaultTableModel 实现类来创建 JTable 对象 。 通过DefaultTableModel 对象创建 JTable 对象后,就可以调用它提供的方法来添加数据行、插入数据行 、删除数据行和移动数据行 。 DefaultTableModel 提供了如下几个方法来控制数据行操作:
     
     

    TableColumnModel和监听器

    JTable 使用 TableColumnModel 来保存该表格所有数据列的状态数据,如果程序需要访问 JTable 的所有列状态信息,则可以通过获取该 JTable 的 TableColumnModel 来实现 。 TableColumnModel 提供了如下几个方法来增加、删除和移动数据列 :
    1. addColumn(TableColumn aColumn): 该方法用于为 TableModel 添加一列 。 该方法主要用于将原来隐藏的数据列显示出来 。
    1. moveColumn(int columnIndex, int newIndex): 该方法用于将指定列移动到其他位置 。
    1. removeColumn(TableColumn column): 该方法用于从 TableModel 中删 除指定列。实际上,该方法并未真正删除指定列,只是将该列在TableColumnModel 中隐藏起来,使之不可见 。
    JTable中也提供了类似的方法完成列的操作,只是其底层依然是通过TableColumnModel来完成的。
    如果程序需要监昕 JTable 里列状态的改变,例如监听列的增加、删除 、 移动等改变, 则必须使用该 JTable 所对应的 TableColumnModel 对象,该对象提供了 一个 addColumnModelListener()方法来添加监听器, 该监听器接口里包含如下几个方法 :
    1. columnAdded(TableColumnModelEvent e) : 当向 TableColumnModel 里添加数据列时将会触发该方法。
    1. columnMarginChanged(ChangeEvent e) : 当由于页面距 ( Margin ) 的改变引起列状态改变时将会触发该方法 。
    1. columnMoved(TableColumnModelEvent e): 当移动 TableColumnModel 里的数据列时将会触发该方法 。
    1. columnRemoved(TableColumnModelEvent e): 当删除 TableColumnModel 里的数据列时将会触发该方法 。
    1. columnSelectionChanged(ListSelectionEvent e): 当改变表格的选择模式时将会触发该方法。
    但表格的数据列通常需要程序来控制增加、 删除 ,用户操作通常无法直接为表格增加 、删除数据列,所以使用监听器来监听 TableColumnModel 改变的情况比较少见。
     
     

    实现列排序

    使用 JTable 实现的表格并没有实现根据指定列排序的功能 , 但开发者可以利用 AbstractTableModel 类来实现该功能。由于 TableModel 不强制要求保存表格里的数据,只要 TableModel 实现了 getValueAt()、getColumnCount()和 getRowCount()三个方法, JTable 就可以根据该 TableModel 生成表格 。 因此可以创建个 SortableTableModel 实现类 , 它可以将原 TableModel 包装起来,并实现根据指定列排序的功能 。
    程序创建的 SortableTableModel 实现类会对原 TableModel 进行包装,但它实际上并不保存任何数据,它会把所有的方法实现委托给原 TableModel 完成。 SortableTableModel 仅保存原 TableModel 里每行的行索引, 当程序对 SortableTableModel 的指定列排序时, 实际上仅仅对SortableTableModel 里的行索引进排序一一这样造成的结果是 : SortableTableModel 里的数据行的行索引与原 TableModel 里数据行的行索引不一致,所以对于 TableModel 的那些涉及行索引的方法都需要进行相应的转换。下面程序实现了SortableTableModel 类,并使用该类来实现对表格根据指定列排序的功能 。
    案例:
    双击列的头部,按照该列从小到大的顺序进行排序
     

    绘制单元格内容

    前面看到的所有表格的单元格内容都是宇符串,实际上表格的单元格内容也可以是更复杂的内容。JTable 使用 TableCellRenderer 绘制单元格, Swing 为该接口提供了 一 个实现类 : DefaultTableCellRenderer,该单元格绘制器可以绘制如下三种类型的单元格值(根据其 TableModel 的 getColurnnClass()方法来决定该单元格值的类型) :
    1. Icon: 默认的单元格绘制器会把该类型的单元格值绘制成该Icon对象所代表的图标 。
    1. Boolean: 默认的单元格绘制器会把该类型的单元格值绘制成复选按钮。
    1. Object: 默认的单元格绘制器在单元格内绘制出该对象的 toString()方法返回的字符串 。
    在默认情况下,如果程序直接使用 二维数组或 Vector 来创建 JTable , 程序将会使用 JTable 的匿名内部类或 DefaultTableModel 充当该表格的 model 对象,这两个 TableModel 的 getColumnClass()方法的返回值都是 Object 。 这意味着,即使该二维数组里值的类型是 Icon , 但由于两个默认的 TableModel 实现类的 getColumnClass()方法总是返回 Object,这将导致默认的单元格绘制器把 Icon 值当成 Object 值处 理一一只是绘制出其 toString()方法返回的字符串。
    为了让默认的单元格绘制器可以将 Icon 类型 的值绘制成图标,把 Boolean 类型的值绘制成复边框 ,创建 JTable 时所使用的 TableModel 绝不能采用默认的 TableModel ,必须采用扩展后的 TableModel 类,如下所示 :
    提供了上面的 ExtendedTableModel 类之后 , 程序应该先创建 ExtendedTableModel 对象,再利用该对象来创建 JTable,这样就可以保证 JTable 的 model 对象的 getColumnClass()方法会返回每列真实的数据类型,默认的单元格绘制器就会将 Icon 类型的单元格值绘制成图标 , 将 Boolean 类型 的单元格值绘制成复选框。
    如果希望程序采用自己定制的单元格绘制器,则必须实现自己的单元格绘制器,单元格绘制器必须实现 TableCellRenderer 接口。与前面的TreeCellRenderer 接口完全相似, 该接口里也只包含一 个getTableCellRendererComponent()方法,该该方法返回的 Component 将会作为指定单元格绘制的组件。
    一旦实现了自己的单元格绘制器之后,还必须将该单元格绘制器安装到指定的 JTable 对象上,为指定的 JTable 对象安装单元格绘制器有如下两种方式 :
    1. 局部方式 ( 列级 ) : 调用 TableColumn的setCellRenderer()方法为指定列安装指定的单元格绘制器。
    1. 全局方式 (表级) :调用 JTable 的setDefaultRendererO方法为指定的 JTable 对象安装单元格绘制器, setDefaultRendererO方法需要传入两个参数,即列类型和单元格绘制器 , 表明指定类型的数据列才会使用该单元格绘制器 。
     
     

    编辑单元格内容

    如果用户双击 JTable 表格的指定单元格,系统将会开始编辑该单元格的内容。在默认情况下,系统会使用文本框来编辑该单元格的内容,与此类似的是 ,如果用户双击 JTree 的节 点,默认也会采用文本框来编辑节点 的内容 。
    但如果单元格内容不是文字内容,用户当然不希望使用文本编辑器来编辑该单元格的内容,因为这种编辑方式非常不直观,用户体验相当差 。 为了避免这种情况,可以实现自己的单元格编辑器,从而可以给用户提供更好的操作界面。
    实现 JTable 的单元格编辑器应该实现 TableCellEditor 接口 ,Swing 为 TableCellEditor提供了 DefaultCellEditor 实现类,efaultCellEditor 类有三 个构造器, 它们分别使用文本框、复选框和JComboBox 作 为单元格编辑器,其中使用文本框编辑器是最常见的情形,如果单元格的值是 Boolean 类型 ,则系统默认使用复选框编辑器。如果想指定某列使用 JComboBox 作为单元格编辑器,则需要显式创建 JComboBox 实例 ,然后以此实例来创建 DefaultCellEditor 编辑器 。
    使用DefaultCellEditor步骤:
    1. 自定义类,继承DefaultCellEditor,重写getTableCellEditorComponent()方法;
    1. 创建自定义类对象
    1. 为JTable安装单元格编辑器
     
    演示代码:
     
  2. Java
  3. Java-GUI
  4. HTML中元素的id属性ForkJoin
    目录