jtable 订阅
JTable 用来显示和编辑常规二维单元表。有关面向任务的文档和使用 JTable 的示例,请参阅 The Java Tutorial 中的 How to Use Tables 一节。 展开全文
JTable 用来显示和编辑常规二维单元表。有关面向任务的文档和使用 JTable 的示例,请参阅 The Java Tutorial 中的 How to Use Tables 一节。
信息
参考文献
The Java Tutorial
出    处
How to Use Tables 一节
用    途
显示和编辑常规二维单元表
中文名
jtable
jtable基本信息
JTableextends JComponentimplements TableModelListener, Scrollable, TableColumnModelListener, ListSelectionListener, CellEditorListener, Accessible, RowSorterListenerJTable 有很多用来自定义其呈现和编辑的工具,同时提供了这些功能的默认设置,从而可以轻松地设置简单表。例如,要设置一个 10 行 10 列的表: TableModel dataModel = new AbstractTableModel() { public int getColumnCount() { return 10; } public int getRowCount() { return 10;} public Object getValueAt(int row, int col) { return new Integer(row*col); } }; JTable table = new JTable(dataModel); JScrollPane scrollpane = new JScrollPane(table); 注意,如果要在单独的视图中(在 JScrollPane 外)使用 JTable 并显示表标题,则可以使用 getTableHeader() 获取并单独显示它。 要启用行的排序和过滤,请使用 RowSorter。可以通过以下两种方式之一设置一个行排序器。 直接设置 RowSorter。例如:table.setRowSorter(new TableRowSorter(model))。将 autoCreateRowSorter 属性设置为 true,从而 JTable 可用于创建 RowSorter。例如:setAutoCreateRowSorter(true)。设计使用 JTable 的应用程序时,务必要注意用来表示表数据的数据结构。DefaultTableModel 是一个模型实现,它使用一个 Vector 来存储所有单元格的值,该 Vector 由包含多个 Object 的 Vector 组成。除了将数据从应用程序复制到 DefaultTableModel 中之外,还可以用 TableModel 接口的方法来包装数据,这样可将数据直接传递到 JTable,如上例所示。这通常可以提高应用程序的效率,因为模型可以自由选择最适合数据的内部表示形式。在决定使用 AbstractTableModel 还是使用 DefaultTableModel 方面有一个好的实践经验,即在创建子类时使用 AbstractTableModel 作为基类,在不需要创建子类时则使用 DefaultTableModel。 源分布演示部分中的 "TableExample" 目录给出了许多 JTable 用法的完整示例,包括如何使用 JTable 来提供一个可编辑的数据视图(数据取自数据库),以及如何修改显示的列以使用指定的渲染器和编辑器。 JTable 使用专有的整数来引用它所显示的模型的行和列。JTable 采用表格的单元格范围,并在绘制时使用 getValueAt(int, int) 从模型中获取值。务必记住各种 JTable 方法所返回的列和行索引是就 JTable(视图)而言的,不一定是模型所使用的那些索引。 默认情况下,在 JTable 中对列进行重新安排,这样在视图中列的出现顺序与模型中列的顺序不同。但这根本不影响模型的实现:当列重新排列时,JTable 在内部保持列的新顺序,并在查询模型前转换其列索引。 因此编写 TableModel 时,不必侦听列的重排事件,因为不管视图怎样,模型都将在其自己的坐标系统被查询。在示例部分中有一个排序算法的演示,此演示正是使用了此技术在另一个坐标系统中进行排序,其中更改了行顺序,没有更改列顺序。 类似地,使用 RowSorter 提供的排序和过滤功能时,底层 TableModel 不需要知道怎样进行排序,RowSorter 将处理它。对底层 TableModel 使用 JTable 的基于行的方法时,必须进行坐标转换。所有基于 JTable 行的方法都是就 RowSorter 而言的,不一定与底层 TableModel 的方法相同。例如,选择始终是就 JTable 而言的,因此使用 RowSorter 时,需要使用 convertRowIndexToView 或 convertRowIndexToModel 进行转换。以下代码显示了如何将 JTable 的坐标转换为底层模型的坐标
收起全文
精华内容
参与话题
问答
  • JTable

    万次阅读 2012-09-10 11:58:08
     利用 JTable 类,可以以表格的形式展示数据,可设置允许用户编辑数据。JTable 本身不拥有或者缓存数据;它只是数据的视图。这里有一个放在滚动面板上的典型表格:  本文展示如何完成一些常见的表格...

    如何使用Table

        利用 JTable 类,可以以表格的形式展示数据,可设置允许用户编辑数据。JTable 本身不拥有或者缓存数据;它只是数据的视图。这里有一个放在滚动面板上的典型表格:



         本文展示如何完成一些常见的表格相关的任务:包括以下部分:

    (1)创建一个简单的表格

    (2)向容器添加表格

    (3)改变每每一栏的宽度

    (4)用户选择

    (5)创建表格模型

    (6)监听数据改变

    (7)点燃数据改变事件

    (8)概念:编辑器和渲染器

    (9)使用自定义渲染器

    (10)为单元格指定提示工具

    (11)为列头指定提示工具

    (12)排序和过滤

    (13)使用组合框作为编辑器

    (14)使用其他编辑器

    (15)使用编辑器验证用户的文本输入

    (16)打印

    (17)例子列表

     

    (1)创建一个简单的表格

        SimpleTableDemo.java 中的表格在一个字符串数组中声明各个列名

    Java代码  收藏代码
    1. String[] columnNames = {"First Name",  
    2.                         "Last Name",  
    3.                         "Sport",  
    4.                         "# of Years",  
    5.                         "Vegetarian"};  

        数据初始化并存储在二维数组:

    Java代码  收藏代码
    1. Object[][] data = {  
    2.     {"Kathy""Smith",  
    3.      "Snowboarding"new Integer(5), new Boolean(false)},  
    4.     {"John""Doe",  
    5.      "Rowing"new Integer(3), new Boolean(true)},  
    6.     {"Sue""Black",  
    7.      "Knitting"new Integer(2), new Boolean(false)},  
    8.     {"Jane""White",  
    9.      "Speed reading"new Integer(20), new Boolean(true)},  
    10.     {"Joe""Brown",  
    11.   
    12.      "Pool"new Integer(10), new Boolean(false)}  
    13. };  

        接着表格使用这些数据和列名构造一个表格:

    Java代码  收藏代码
    1. JTable table = new JTable(data, columnNames);  

        有两个接收数据的 JTable 构造器:

    • JTable(Object[][] rowData, Object[] columnNames)
    • JTable(Vector rowData, Vector columNames)

        这些构造函数的好处是容易实现,而缺点是:

    • 他们自动设置每个单元格为可编辑
    • 数据类型都视为一样的(字符串类型)。例如,如果表格的一列有 Boolean 数据,表格用单选框来展示这个数据。可是,如果你用上面两种构造,你的 Boolean 数据将显示为字符串,就像前面表格截图中的 Vegetarian 一列一样。
    • 它们要求你把所有表格数据放入一个数组或者vector,这些数据结构可能不适合某些数据类型。例如,如果你实体化一组数据库对象,比起拷贝所有值放入数组和vector,你可能仅仅想要直接查询这些对象的值。

        如果你想避免这些限制,你需要实现你自己的表格模型,见“(5)创建表格模型”。

     

    (2)向容器添加表格

        这里有一段创建滚动面板作为表格容器的常规代码:

    Java代码  收藏代码
    1. JScrollPane scrollPane = new JScrollPane(table);  
    2. table.setFillsViewportHeight(true);  

        这两行代码实现了:表格对象的引用作为 JScrollPane 构造函数的参数,创建一个容纳table的容器,table添加到容器中;JTable.setFillsViewportHeight 方法设置了 fillsViewportHeight 属性。当这个属性为 true 时,表格会占据容器整个高度,即便表格没有足够的行去使用这些垂直空间。这使得表格更容易实现拖拉操作。

     

        滚动面板自动把表格头放置在视窗的顶端。当表格数据垂直滚动时,列名保持在视窗顶端可视。

     

        如果你想要使用一个没有滚动面板的表格,你必须获得表格头组件,然后自己放置它,例如:

    Java代码  收藏代码
    1. container.setLayout(new BorderLayout());  
    2. container.add(table.getTableHeader(), BorderLayout.PAGE_START);  
    3. container.add(table, BorderLayout.CENTER);   

     

    (3)改变每每一列的宽度

        默认情况下,表格所有列等宽,切这些列自动填满整个表格的宽度。当表格变宽或者变窄时(通常是用户调整包含表格的窗口大小),所有的列宽自动调整到适当宽度。

     

        当用户通过拖动列头的右边界来调整某一列的宽度时,要么别的列的宽度会受到影响而改变,要么整个表格的宽度会改变。默认情况下,表格整体宽度保持不变,“拖动点“的右侧各列利用增加或减少的空间自我调整,拖动的那一列的左侧各列保持不变。

     

        要定义各列初始化宽度,你可以对表格各列调用 setPreferredWidth 方法。可以设置各列首选宽度,和他们的相对宽度。例如,向demo增加下面代码,是的第三列比其他列更宽:

    Java代码  收藏代码
    1. TableColumn column = null;  
    2. for (int i = 0; i < 5; i++) {  
    3.     column = table.getColumnModel().getColumn(i);  
    4.     if (i == 2) {  
    5.         column.setPreferredWidth(100); //third column is bigger  
    6.     } else {  
    7.         column.setPreferredWidth(50);  
    8.     }  
    9. }  

     

       如上面代码所示,每一列代表一个 TableColumn 对象, TableColumn 提供 getter 和 setter 方法设置和获取列的最小、首选、最大宽度 和 目前宽度。 基于估计单元格内容需要的空间调整单元格宽度,查看TableRenderDemo.java. 中的 initColumnSizes 方法。

     

        当用户明确的调整列宽度,列的”首选宽度“就被设置为用户指定的”新的当前宽度“。不过,当表格因视窗调整而改变大小是,列的”首选宽度“不会改变。”首选宽度“的存在是用于计算新的列的宽度,来填充可用空间。

     

        你可以通过调用 setAutoResizeMode 改变一个表格的调整模式。

     

    (4)用户选择

        默认配置情况下,一个表格支持选择一行或多行。用户可以选择一组连续的或不连续的行。用户最后指示的那个单元格,在 Metal 样式中,会被outlined(轮廓虚线)。这个单元格被称为 ”lead selection“(导联选择(器, 钮));有时候也称为 ”聚焦单元格“ 或 ”当前单元格“。

     

       用户使用鼠标键盘实现选择,选择的方式描述如下

     

    操作
    鼠标动作
    键盘动作
    选择单行 点击 向上或向下
    选中连续多行 Shift—点击/拖拉 Shitf-向上 或 Shift-向下

     

    向选中的行集增加行/切换选择

    Control-点击 Control+向上或向下, 使用空格键增加当前行或切换选择.

     

        下面的例子程序TableSelectionDemo.java展示了类似的表格,允许用户操纵某些 JTable 选项。还有一个文本面板记录”选择事件“。(这个demo里面的有关复选框事件处理代码写的好好)

     

        在下面的截图中,这事默认的Metal样式,选中的行highlight,选择的单元格outline


        在下面的”Selection Mode“下,有一些复选框,选择”Single Selection“。现在你只能在某一时刻选中一行,如果你选中”Single Interval Selection“,你可以选择连续的多行。

     

        所有的”Selection Mode“下面的复选框按钮,调用 JTable.setSelectionMode. 这个方法带一个参数,为javax.swing.ListSelectionModelMULTIPLE_INTERVAL_SELECTIONSINGLE_INTERVAL_SELECTION, andSINGLE_SELECTION.中的一个(依次为,多行可间隔,多行无间隔,单行)

     

        回到我们的 demo,注意,在”Selection Options“下三个复选框,每个复选框控制一个由 JTable 定义的绑定属性的boolean类型状态值:

    • ”Row Selection“控制 控制 rowSelectionAllowed 属性,通过setRowSelectionAllowed 和getRowSelectionAllowed 设置和读取。当这个绑定属性为 true (同时 columnSelectionAllowed属性为 false)时,用户可以选择行。
    • ”Coolumn Selection“控制 columnSelectionAllowed 属性,通过setColumnSelectionAllowedgetColumnSelectionAllowed 设置和读取。当这个绑定属性为 true 时,用户可以选择单个单元格,或者呈矩阵块地选择多个单元格
    • ”Cell Selection“控制 cellSelectionEnabled,通过 setCellSelectionEnabled andgetCellSelectionEnabled 设置和获取。当这个绑定属性为 true 是,用户可以选择单个单元格,或是以矩阵块的形式选择多个单元格。

        提醒:JTable使用很简单的选择原则来管理 行 和 列 的交集,它并非设计成全面处理独立的单元格选择。(就是说,有些多单元格的选择是不被handle的,你也选不到)

     

        如果你清空三个复选框,就没有selection了,只有lead selection表现而已。(我觉得lead selection只是形式上的选择,是一种导航观察的形式,而selection是确切选中表格中某些单元格的事实。我无法确切地解释出lead selection 和 selection的区别,我只能意会呀)

     

        你可能注意到”Cell Selection“复选框在”multiple interval selection“选择模式中是不可用的。只是在这个demo的模式中是不被支持的。你可以在”multiple interval selection“模式中指定单元格选择,但是表格也不会产生有效的selection。

     

        你或许还注意到,改变这”selection option“中某个选项可能影响其他选项。这是因为允许行选择和列选择,就意味着允许单元格原则。JTable自动更新三个绑定属性,以保持它们的一致性。

     

        提醒:设置 cellSelectionEnabled 的值会附带同时设置 rowSelectionEnabled 和 columnSelectionEnabled 的效果。同样,设置后两者的值同样会影响 cellSelectionEnabled 的值。设置 row……和 cloumn……为不同值,同时设置 cell……为 false,可以测试一下。

     

        要获得当前的selection,使用 JTable.getSelectedRows,返回一个带索引行数的数组,使用 JTable.getSelectedColumns 返回 列索引。 要获得 lead selection 的坐标,需要引用table本身的 selection model 和 table 的 column model。下面代码格式化一个包含一个lead selection的行和列的字符串:

    Java代码  收藏代码
    1. String.format("Lead Selection: %d, %d. ",  
    2.     table.getSelectionModel().getLeadSelectionIndex(),  
    3.     table.getColumnModel().getSelectionModel().getLeadSelectionIndex());  

        使用selections产生一些时间。参考 How to Write a List Selection Listener in the Writing Event Listeners

     

    (5)创建表格模型

        每个 table 对象 使用一个 table model 对象来管理表格中真实的数据。一个 table model 对象一定要实现 TableModel 接口,如果程序没有提供一个 table model 对象,JTable自动创建一个 DefaultTableModel实例。这种关系可用下面的图来解释


        SimpleTableDemo 中 JTable 的构造器如下面代码一样,创建它的 table model:

    Java代码  收藏代码
    1. new AbstractTableModel() {  
    2.     public String getColumnName(int col) {  
    3.         return columnNames[col].toString();  
    4.     }  
    5.     public int getRowCount() { return rowData.length; }  
    6.     public int getColumnCount() { return columnNames.length; }  
    7.     public Object getValueAt(int row, int col) {  
    8.         return rowData[row][col];  
    9.     }  
    10.     public boolean isCellEditable(int row, int col)  
    11.         { return true; }  
    12.     public void setValueAt(Object value, int row, int col) {  
    13.         rowData[row][col] = value;  
    14.         fireTableCellUpdated(row, col);  
    15.     }  
    16. }  

        上面代码,简单的实现了一个 table model。通常在 AbstractTableModel 的子类中实现 table model。

     

        你的模型可以支持 数组、vector 或 hash map类型的数据。甚至是从外资资源,如数据库中获得数据。他甚至可以在运行期间产生数据。

     

        这个TableDemo.java例子中的表格与前面 SimpleTableDemo 中的表格有几点区别:

    •   TableDemo的自定义 table model,即便它很简单,不过他可以轻松地确定数据的类型,帮助 JTable 用最好的格式展示数据。 SimpleTableDemo 自动创建的 table model, 并不知道 # of Years 一栏包括数字(需要右对齐且特殊格式),也不知道 Vegetarian 一栏包含用单选框表示的布尔值。
    • 在 TableDemo 中实现的 table model 并不是让你编辑那些表示姓名的栏目,而是修改其他栏。在 SimpleTableDemo中,所有单元格都是可编辑的。

    观察 TableDemo.java 的代码,粗体部分是区别于 SimpleTableDemo自动创建的 table model:

    Java代码  收藏代码
    1. public TableDemo() {  
    2.     ...  
    3.     JTable table = new JTable(new MyTableModel());  
    4.     ...  
    5. }  
    6.   
    7. class MyTableModel extends AbstractTableModel {  
    8.     private String[] columnNames = ...//same as before...  
    9.     private Object[][] data = ...//same as before...  
    10.   
    11.     public int getColumnCount() {  
    12.         return columnNames.length;  
    13.     }  
    14.   
    15.     public int getRowCount() {  
    16.         return data.length;  
    17.     }  
    18.   
    19.     public String getColumnName(int col) {  
    20.         return columnNames[col];  
    21.     }  
    22.   
    23.     public Object getValueAt(int row, int col) {  
    24.         return data[row][col];  
    25.     }  
    26.   
    27.     <strong>public Class getColumnClass(int c) {  
    28.         return getValueAt(0, c).getClass();  
    29.     }</strong>  
    30.   
    31.   
    32.   
    33.   
    34.     /* 
    35.      * Don't need to implement this method unless your table's 
    36.      * editable. 
    37.      */  
    38.     public boolean isCellEditable(int row, int col) {  
    39.         //Note that the data/cell address is constant,  
    40.         //no matter where the cell appears onscreen.  
    41.         <strong>if (col < 2) {  
    42.             return false;  
    43.         } else {  
    44.             return true;  
    45.         }</strong>  
    46.   
    47.   
    48.   
    49.     }  
    50.   
    51.     /* 
    52.      * Don't need to implement this method unless your table's 
    53.      * data can change. 
    54.      */  
    55.     public void setValueAt(Object value, int row, int col) {  
    56.         data[row][col] = value;  
    57.         fireTableCellUpdated(row, col);  
    58.     }  
    59.     ...  
    60. }  
     

    (6)监听数据改变

        一个 table model 可以有多个监听器,无论何时,只要表格数据被改变,都会通知这些监听器。监听器是TableModelListener 类的实例。在下面的例子代码中, SimpleTableDemo 增加了一个监听器,粗体部分是新的代码:

     

    Java代码  收藏代码
    1. <strong>import javax.swing.event.*;  
    2. import javax.swing.table.TableModel;</strong>  
    3.   
    4.   
    5.   
    6.   
    7. public class SimpleTableDemo ...<strong> implements TableModelListener </strong>  
    8.   
    9.   
    10. {  
    11.     ...  
    12.     public SimpleTableDemo() {  
    13.         ...  
    14.     <strong>    table.getModel().addTableModelListener(this);</strong>  
    15.   
    16.   
    17.         ...  
    18.     }  
    19.   
    20.     <strong>public void tableChanged(TableModelEvent e) {  
    21.         int row = e.getFirstRow();  
    22.         int column = e.getColumn();  
    23.         TableModel model = (TableModel)e.getSource();  
    24.         String columnName = model.getColumnName(column);  
    25.         Object data = model.getValueAt(row, column);  
    26.   
    27.         ...// Do something with the data...  
    28.     }</strong>  
    29.   
    30.   
    31.     ...  
    32. }  

     

    (7)点燃数据改变事件

        为了唤醒数据改变事件,table model一定要知道如果构造 TableModelEvent 对象。这是个复杂的过程,但是已经在 DefaultTableModel 中实现了。你可以让 JTable 使用他自己默认的 DefaultTableModel 实例,或者创建自定义的 DefaultTableModel 子类。

     

        如果 DefaultTableModel 不适合作为自定义 table model 类的基类,考虑使用 AbstractTableModel 作为基类。这个类实现了构造 TableModelEvent 对象的简单框架。(DefaultTableModel 是该抽象类的子类)当外界改变了表格数据的时候,你的自定义类仅仅需要调用 AbstractTableModel 方法中的一个,如下:

     

    Method Change
    fireTableCellUpdated Update of specified cell. 单元格更新
    fireTableRowsUpdated Update of specified rows 行更新
    fireTableDataChanged Update of entire table (data only). 表格范围内的数据更新
    fireTableRowsInserted New rows inserted. 插入新行
    fireTableRowsDeleted Existing rows Deleted 删除存在的行
    fireTableStructureChanged   Invalidate entire table, both data and structure. 使表格无效,包括数据和结构

     

     

    (8)概念:编辑器和渲染器(Editors and Renderers)

        在进行后面的学习前,你需要理解表格是如何绘制它的单元格的。你可能会认为表格中每个单元格都是一个组件,但是,考虑性能的原因,Swing的表格并不这么做。

     

        取而代之的是,一个 single cell renderer(单一单元格绘制器)一般用来绘制所有包含同类型数据的单元格。你可以想象这个 renderer 是一个可配置的墨水打印,表格使用它将格式化的数据合适地印在每个单元格上。当用于开始编辑一个单元格的数据时, cell editor 接管这个单元格,控制单元格的编辑行为。

     

        例如,TableDemo 的 # of Years 列中的每个单元格包含数字数据——具体是一个Integer对象。默认情况下,对于数字列,渲染器使用单个 JLabel 实例在列上的单元格绘制恰当的居右的数字。如果用户开始编辑一个单元格,则默认的单元格编辑器使用一个 居右的 JTextField 来控制单元格的编辑动作。

     

        如何选择 render 处理某一列的单元格,表格首先会确定,对于该列,你是否已经指定了一个 renderer。如果你未指定,那么 table 会调用 table model 的 getColumnClass 方法,获得该列的单元格的数据的类型。接着,table 会将该列的数据类型与一个数据类型列表对比,该列表注册了多种 cell renderers。该表由 table 初始化,你可以向该表增加renderer。通常,table 会把下列类型放到列表中:

    • Boolean——复选框
    • Number——居右的label
    • Double, Float——类似Number,不过 从 对象 到 文本的转化通过 NumberFormat 的实例来执行。
    • Date——label,对象 到 文本 的转换通过 DateFormat 的实例来执行。
    • ImageIcon,Icon——居中的label
    • Object——展示了对象的字符串值的label

        单元格编辑器使用类似的法则。

     

        注意,如果让 table 自己创建它的 model,它会把 Object 作为各列的类型。为了指定更明确列类型,table model一定要定义适当的 getColumnClass 方法,像 TableDemo.java. 中的定义那样。

     

        记住,尽管 render 决定有多少单元格和列头被指定了它的 tool tip text(鼠标指在上面显示的提示文本),但是 render 本身不处理事件。如果你需要获得 table 内发生的事件,你使用的技术就是在下面分类的事件中做变化:

    Situation How to Get Events
    To detect events from a cell that is being edited... Use the cell editor (or register a listener on the cell editor).
    To detect row/column/cell selections and deselections... Use a selection listener as described in Detecting User Selections.
    To detect mouse events on a column header... Register the appropriate type of mouse listener on the table'sJTableHeader object. (See TableSorter.java for an example.)
    To detect other events... Register the appropriate listener on the JTable object.

     

     

    (9)使用自定义渲染器

        这节的内容将告诉你如何创建和指定一个 cell renderer。你可以使用 JTable 的 setDefaultRenderer 方法设置一个类型明确的 cell renderer。使用 TableColumn 的 setCellRenderer 方法,可以指定某列中的单元格使用的 renderer。你甚至可以通过创建 JTable 的子类来指定 cell-specific renderer(针对某个单元格的renderer)。

     

        通过默认的renderer, DefaultTableCellRenderer,很容易自定义 text 和 image renderer。你只需要创建一个子类,实现 setValue 方法,这样它就会调用 setText(合适的字符串参数) 或 setIcon(合适的图像)。例如,这里给出默认的 date renderer 的实现:

    Java代码  收藏代码
    1. static class DateRenderer extends DefaultTableCellRenderer {  
    2.     DateFormat formatter;  
    3.     public DateRenderer() { super(); }  
    4.   
    5.     public void setValue(Object value) {  
    6.         if (formatter==null) {  
    7.             formatter = DateFormat.getDateInstance();  
    8.         }  
    9.         setText((value == null) ? "" : formatter.format(value));  
    10.     }  
    11. }  

        如果只是继承 DefaultTableCellRenderer 是不够的,你可以使用另外一个超类来构建 renderer。最简单的方法就是创建一个存在的空间的子类,让该子类实现 TableCellRenderer 接口。 TableCellRenderer 只要求一个方法: getTableCellRendererComponent。这个方法的实现了 建立 渲染组件 绘制具体的状态,然后返回这个组件。

     

       在下面的 TableDialogEditDemo.java 的截图中, 用于处理列 Favorite Color一栏的单元格的 renderer,是 JLabel 的子类,名为ColorRenderer。


        这里引用 ColorRenderer.java 中的代码:

    Java代码  收藏代码
    1. public class ColorRenderer extends JLabel  
    2.                            implements TableCellRenderer {  
    3.     ...  
    4.     public ColorRenderer(boolean isBordered) {  
    5.         this.isBordered = isBordered;  
    6.         setOpaque(true); //MUST do this for background to show up.  
    7.     }  
    8.   
    9.     public Component getTableCellRendererComponent(  
    10.                             JTable table, Object color,  
    11.                             boolean isSelected, boolean hasFocus,  
    12.                             int row, int column) {  
    13.         Color newColor = (Color)color;  
    14.         setBackground(newColor);  
    15.         if (isBordered) {  
    16.             if (isSelected) {  
    17.                 ...  
    18.                 //selectedBorder is a solid border in the color  
    19.                 //table.getSelectionBackground().  
    20.                 setBorder(selectedBorder);  
    21.             } else {  
    22.                 ...  
    23.                 //unselectedBorder is a solid border in the color  
    24.                 //table.getBackground().  
    25.                 setBorder(unselectedBorder);  
    26.             }  
    27.         }  
    28.           
    29.         setToolTipText(...); //Discussed in the following section  
    30.         return this;  
    31.     }  
    32. }  

     

        下面这句代码是TableDialogEditDemo.java 中注册 ColorRender实例为 所有 Color 类数据的 默认 renderer。    

    Java代码  收藏代码
    1. table.setDefaultRenderer(Color.classnew ColorRenderer(true));  

     

        要指定一个 cell-specific renderer,你需要定义一个 JTable 子类,覆盖 getCellRenderer 方法。例如,下面代码指定第一列第一个单元格使用一个自定义的 renderer:

    Java代码  收藏代码
    1. TableCellRenderer weirdRenderer = new WeirdRenderer();  
    2. table = new JTable(...) {  
    3.     public TableCellRenderer getCellRenderer(int row, int column) {  
    4.         if ((row == 0) && (column == 0)) {  
    5.             return weirdRenderer;  
    6.         }  
    7.         // else...  
    8.         return super.getCellRenderer(row, column);  
    9.     }  
    10. };  

     

    (10)为单元格指定提示工具

        默认情况下,tool tip text(提示文本) 是否展示取决于单元格的 renderer。不过,有时候可以通过覆盖 JTable 的 getToolTipText(MouseEvent) 方法来指定 tool tip text。这节将告诉你这两种技术:

     

        使用单元格的 renderer 增加文本提示,首先你要获得或创建一个 cell renderer。然后,在确保 这个 rendering component 是一个 JComponent后,调用 setToolTipText。(之前的ColorRender 继承了 JLabel,所以它是个JComponent,同时它也实现了TableCellRenderer,所以它是一个 rendering component)

     

        TableRenderDemo.java.的源代码。它对 Sport 列 增加了文本提示:

    Java代码  收藏代码
    1. //Set up tool tips for the sport cells.  
    2. DefaultTableCellRenderer renderer =  
    3.         new DefaultTableCellRenderer();  
    4. renderer.setToolTipText("Click for combo box");  
    5. sportColumn.setCellRenderer(renderer);  

        虽然这个文本提示设置是静态的,但是你可以实现 依赖于单元格或者程序的 动态文本提示(前面的ColorRender中有关tool tip 的设置也是一种方法):

    • 在renderer 实现的 getTableCellRendererComponent 方法中增加一点代码
    • 覆盖 JTable 的 getToolTipText(MouseEvent)方法。

     

        TableDialogEditDemo 对Color类型栏使用一个renderer,见 ColorRenderer.java, 粗体部分为设置tool tip text 部分的代码:

    Java代码  收藏代码
    1. public class ColorRenderer extends JLabel   
    2.                            implements TableCellRenderer {  
    3.     ...  
    4.     public Component getTableCellRendererComponent(  
    5.                             JTable table, Object color,  
    6.                             boolean isSelected, boolean hasFocus,  
    7.                             int row, int column) {  
    8.         Color newColor = (Color)color;  
    9.         ...  
    10.         setToolTipText("RGB value: " + newColor.getRed() + ", "  
    11.                                      + newColor.getGreen() + ", "  
    12.                                      + newColor.getBlue());  
    13.         return this;  
    14.     }  
    15. }  

     

       tool tip的效果如下:


        你可以通过覆盖 JTable 的 getToolTipText(MouseEvent)方法指定 tool tip text。

     

        这个demo设置了 Sport 和 Vegetarian栏中的单元格给出文本提示:



     
    TableToolTipsDemo.java 中实现了Sport 和 VegeTarian 栏中单元格给出文本提示的代码如下:

    Java代码  收藏代码
    1. JTable table = new JTable(new MyTableModel()) {      
    2.     //Implement table cell tool tips.  
    3.     public String getToolTipText(MouseEvent e) {  
    4.         String tip = null;  
    5.         java.awt.Point p = e.getPoint();  
    6.         int rowIndex = rowAtPoint(p);  
    7.         int colIndex = columnAtPoint(p);  
    8.         int realColumnIndex = convertColumnIndexToModel(colIndex);  
    9.   
    10.         if (realColumnIndex == 2) { //Sport column  
    11.             tip = "This person's favorite sport to "  
    12.                    + "participate in is: "  
    13.                    + getValueAt(rowIndex, colIndex);  
    14.   
    15.         } else if (realColumnIndex == 4) { //Veggie column  
    16.             TableModel model = getModel();  
    17.             String firstName = (String)model.getValueAt(rowIndex,0);  
    18.             String lastName = (String)model.getValueAt(rowIndex,1);  
    19.             Boolean veggie = (Boolean)model.getValueAt(rowIndex,4);  
    20.             if (Boolean.TRUE.equals(veggie)) {  
    21.                 tip = firstName + " " + lastName  
    22.                       + " is a vegetarian";  
    23.             } else {  
    24.                 tip = firstName + " " + lastName  
    25.                       + " is not a vegetarian";  
    26.             }  
    27.   
    28.         } else { //another column  
    29.             //You can omit this part if you know you don't   
    30.             //have any renderers that supply their own tool   
    31.             //tips.  
    32.             tip = super.getToolTipText(e);  
    33.         }  
    34.         return tip;  
    35.     }  
    36.     ...  
    37. }  

     

       除了 converColumnIndexToModel 的调用意外,这段代码很容易明白。这个方法是必需的,因为用户可能在界面上移动了某些列,视图上的某列索引并不匹配 table model 中该列的索引,而数据处理是在 table model 上操作的,所以要获得对应于 table model 中该列的索引。

     

    (11)为列头指定工具集

        你可以通过设置 table 的 JTableHeader 对象,增加列头的文本提示。不同的列头常常需要不同的文本提示,你可以覆盖 table header 的 getToolTipText 方法来改变提示文本。你也可以 调用 TableColumn.setHeaderRenderer, 对 header 指定自定义的 renderer.

     

        TableToolTipsDemo.java 中也有根据不同列显示不同列头文本提示的例子,如下图,当你将鼠标移动到后三列的列头上时,将显示提示文本。而前两列的列头未提供文本提示(名字已经充分说明这列数据,无需别的提示说明),以下是功能截图:


        下面代码实现了上面的文本提示功能。创建一个 JTableHeader 子类,覆盖 getToolTipText(MouseEvent)方法,这样就能对当前列返回文本。要与 table 关联这个修订过的 header,使用 JTable 的 createDefaultTableHeader 方法,返回一个 JTableHeader 子类实例。

    Java代码  收藏代码
    1. protected String[] columnToolTips = {  
    2.     null// "First Name" assumed obvious  
    3.     null// "Last Name" assumed obvious  
    4.     "The person's favorite sport to participate in",  
    5.     "The number of years the person has played the sport",  
    6.     "If checked, the person eats no meat"};  
    7. ...  
    8.   
    9. JTable table = new JTable(new MyTableModel()) {  
    10.     ...  
    11.   
    12.     //Implement table header tool tips.  
    13.     protected JTableHeader createDefaultTableHeader() {  
    14.         return new JTableHeader(columnModel) {  
    15.             public String getToolTipText(MouseEvent e) {  
    16.                 String tip = null;  
    17.                 java.awt.Point p = e.getPoint();  
    18.                 int index = columnModel.getColumnIndexAtX(p.x);  
    19.                 int realIndex =   
    20.                         columnModel.getColumn(index).getModelIndex();  
    21.                 return columnToolTips[realIndex];  
    22.             }  
    23.         };  
    24.     }  
    25. };  

     

        提醒:(有关单元格或列头文本提示)上面代码,getToolTipText(MouseEvent e) 和 createDefaultTableHeader 方法都是 JTable 的方法。用了很多匿名类的写法,要注意看仔细。

     

    (12)排序和过滤

        表格 sorting 和 filtering 是由 一个 sorter 对象管理的。获得一个 sorter 对象的最简单方法是设置 autoCreateRowSorter 绑定属性 为true:

    Java代码  收藏代码
    1. JTable table = new JTable();  
    2. table.setAutoCreateRowSorter(true);  

     

        这段代码定义了一个 row sorter,他是 javax.swing.table.TableRowSorter 的实例。当用户点击某列列头时,表格会做一个 locale-specific sort。 TableSortDemo.java,例子的截图:


        你可以构造一个 TableRowSorter 实例,然后指定它为你的 table 的sorter,这样你就能获得更多的分类控制。

    Java代码  收藏代码
    1. TableRowSorter<TableModel> sorter   
    2.     = new TableRowSorter<TableModel>(table.getModel());  
    3. table.setRowSorter(sorter);  

     

        TableRowSorter 使用 java.util.Comparator (实现了该接口的)对象来排序。实现该接口,必须提供一个名为 compare 的方法,该方法定义两个了两个对象的比较值,用于排序。例如,下面代码创建了一个 Comparator,根据字符串最后一个单词来排序。(String实现了Comparable接口)

    Java代码  收藏代码
    1. Comparator<String> comparator = new Comparator<String>() {  
    2.     public int compare(String s1, String s2) {  
    3.         String[] strings1 = s1.split("\\s");  
    4.         String[] strings2 = s2.split("\\s");  
    5.         return strings1[strings1.length - 1]  
    6.             .compareTo(strings2[strings2.length - 1]);  
    7.     }  
    8. };  

     

        这个例子太简单了,更具典型意义的是,实现了Comparator接口的类,同时也是  java.text.Collator.的子类,你可以定义自己的子类,或者使用 Collator 的工厂方法,获得一个支持本地语言的 Comparator,又或是使用 java.text.RuleBasedCollator. ,该类是 Collator 的具体子类。

     

        为了确定某一列使用哪个 Comparator, TableRowSorter 尝试轮流使用一些规则规则。这些规则按顺序的列在下面;第一条规则为 sorter 提供了一个 Comparator,……:

    1. 如果通过调用 setComparator指定了一个比较器,则使用该比较器
    2. 如果这个 table model 反馈,某一列是由字符串组成的(TableModel.getColumnClass 返回 String.class),则使用一个基于当前本地配置的比较器用于字符串排序。
    3. 如果 TableModel.getColumnClass 返回的类型实现了 Comparable,则基于 Comparable.compareTo.返的值对字符串排序。
    4. 如果通过调用 setStringConverter 为 table 指定一个字符串转换器,则对象转换所得的字符串值代表对象,参加基于本地语言的排序。
    5. 如果之前的几条规则都没被采用,则使用一个比较器,该比较器会对列上的数据对象调用 toString,然后根据返回的字符串进行基于本地语言的排序。

        对于更复杂的排序,查阅TableRowSorter 和他的父类 javax.swing.DefaultRowSorter.

     

        调用 setSortKeys ,指定排序规则和优先排序。(有关”键“的概念,对于某一列,使用比较器排序时,无法得出某几行的顺序时,则按照键列表中的键顺序,根据这些键,其实就是列,在原来基础上再次此对这几行排序…………你懂的)这里有一个有一个根据前两列排序的例子。哪一列优先排序是取决于”排序键列表“中的“排序键”顺序。在这个例子中,第二列是第一排序键,所以根据第二列优先排序,然后再根据第一列排序:

    Java代码  收藏代码
    1. List <RowSorter.SortKey> sortKeys   
    2.     = new ArrayList<RowSorter.SortKey>();  
    3. sortKeys.add(new RowSorter.SortKey(1, SortOrder.ASCENDING));  
    4. sortKeys.add(new RowSorter.SortKey(0, SortOrder.ASCENDING));  
    5. sorter.setSortKeys(sortKeys);   

     

        除了对结果集二次排序外,一个 table sorter 可以指定过滤器,让哪些行不显示。TableRowSorter 使用javax.swing.RowFilter 对象实现过滤功能。 RowFilter 实现了几个工厂方法,可以创建集中常用的 filter。例如regexFilter 方法返回一个基于 regular expression.(正则表达式)的 RowFilter。

     

        在下面的例子代码中,明确的创建了一个 sorter 对象,接着可以给它指定一个 filter:

    Java代码  收藏代码
    1. MyTableModel model = new MyTableModel();  
    2. sorter = new TableRowSorter<MyTableModel>(model);  
    3. table = new JTable(model);  
    4. table.setRowSorter(sorter);  

     

        接着你基于当前文本值进行过滤:

    Java代码  收藏代码
    1. private void newFilter() {  
    2.     RowFilter<MyTableModel, Object> rf = null;  
    3.     //If current expression doesn't parse, don't update.  
    4.     try {  
    5.         rf = RowFilter.regexFilter(filterText.getText(), 0);  
    6.     } catch (java.util.regex.PatternSyntaxException e) {  
    7.         return;  
    8.     }  
    9.     sorter.setRowFilter(rf);  
    10. }  
     

        filterText 文本框的值每次改变时,newFilter() 都会被调用。try catch 防止了用户在界面的文本框中输进错误的正则表达式。

     

        当一个 table 使用一个 sorter 时,用户看到的数据顺序可能跟 data model指定的顺序不一样,也许没有包含 data model 指定的所有行。 用户真正看到的数据被称为 “view”,拥有自己的一套坐标。 JTable 提供了方法用于转换 model 坐标 到 view 坐标——convertColumnIndexToView and convertRowIndexToView 方法。当然也提供了model 到 view 的转换——convertColumnIndexToModel and convertRowIndexToModel.

     

        提醒:每次使用 sorter 时,记得转换单元格的索引,数据真正是要在 model 上处理的。

     

        下面代码整合这节所讨论的技术。

        TableFilterDemo.java 对 TableDemo 做了一些修改,包括前面提到的一些代码。这个例子给 table 提供了一个 sorter ,使用一个文本框提供过滤的正则表达式。下面是截图是:未排序 和 未过滤,注意,model中的第三行依然为view 的第三行。


        如果用户点击第二列两次,第四行就会变成第一行——这只是view的改变,model中的列顺序没改变。


        如前面所描述的一样,用户向“Filter Text”文本域输入正则表达式,符合这些表达式的行将被显示。跟排序一样,过滤也是产生 view,与 mode 分离。


        下面的代码,根据当前 selection 更新 status 文本框:

    Java代码  收藏代码
    1. table.getSelectionModel().addListSelectionListener(  
    2.         new ListSelectionListener() {  
    3.             public void valueChanged(ListSelectionEvent event) {  
    4.                 int viewRow = table.getSelectedRow();  
    5.                 if (viewRow < 0) {  
    6.                     //Selection got filtered away.  
    7.                     statusText.setText("");  
    8.                 } else {  
    9.                     int modelRow =   
    10.                         table.convertRowIndexToModel(viewRow);  
    11.                     statusText.setText(  
    12.                         String.format("Selected Row in view: %d. " +  
    13.                             "Selected Row in model: %d.",   
    14.                             viewRow, modelRow));  
    15.                 }  
    16.             }  
    17.         }  
    18. );  

     

    (13)使用combo box作为编辑器

        让 combo box 作为一个 editor 是简单的,下面粗体部分的代码,指定某列的editor 为一个 combo box

    Java代码  收藏代码
    1. TableColumn sportColumn = table.getColumnModel().getColumn(2);  
    2. ...  
    3. JComboBox comboBox = new JComboBox();  
    4. comboBox.addItem("Snowboarding");  
    5. comboBox.addItem("Rowing");  
    6. comboBox.addItem("Chasing toddlers");  
    7. comboBox.addItem("Speed reading");  
    8. comboBox.addItem("Teaching high school");  
    9. comboBox.addItem("None");  
    10. sportColumn.setCellEditor(new DefaultCellEditor(comboBox));  

     

        效果图:


    (14)使用其他编辑器

        无论你是设置一个列的 editor (使用 TableColumn.setCellEditor 方法),还是为一个数据类型设置 eidtor (使用 JTable.setDefaultEditor 方法),你可以指定你个实现了TableCellEditor 的类作为 editor。幸运的是 DefaultCellEditor 类实现了这个借口,并且提供了参数为编辑组件(JTextField,JCheckBox 或 JComboBox)的构造函数。通常你不需要明确的指定一个check box 为 editor,因为 Boolean 类型的数据自动使用 单选框 render 和 editor。

     

        你的单元格 ediotr 类需要定义至少两个方法—— getCellEditorValue 和 getTableCellEditorComponent。getCellEditorValue 返回单元格当前值, 该方法是 CellEditor 接口要求的; getTableCellRendererComponent 返回你想要用作编辑器的组件,该方法是 TableCellEditor 接口要求的。

     

        下面截图包含一个表格和一个对话框,表格使用对话框间接地作为单元格编辑器。当用户开始编辑 Favorite Color 列是,呈现一个按钮(真正的cell editor),带出对话框,让用户选择不同的颜色。


        下面是 ColorEditor.java, 中的代码:

    Java代码  收藏代码
    1. public class ColorEditor extends AbstractCellEditor  
    2.                          implements TableCellEditor,  
    3.                                     ActionListener {  
    4.     Color currentColor;  
    5.     JButton button;  
    6.     JColorChooser colorChooser;  
    7.     JDialog dialog;  
    8.     protected static final String EDIT = "edit";  
    9.   
    10.     public ColorEditor() {  
    11.         button = new JButton();  
    12.         button.setActionCommand(EDIT);  
    13.         button.addActionListener(this);  
    14.         button.setBorderPainted(false);  
    15.   
    16.         //Set up the dialog that the button brings up.  
    17.         colorChooser = new JColorChooser();  
    18.         dialog = JColorChooser.createDialog(button,  
    19.                                         "Pick a Color",  
    20.                                         true,  //modal  
    21.                                         colorChooser,  
    22.                                         this,  //OK button handler  
    23.                                         null); //no CANCEL button handler  
    24.     }  
    25.   
    26.     public void actionPerformed(ActionEvent e) {  
    27.         if (EDIT.equals(e.getActionCommand())) {  
    28.             //The user has clicked the cell, so  
    29.             //bring up the dialog.  
    30.             button.setBackground(currentColor);  
    31.             colorChooser.setColor(currentColor);  
    32.             dialog.setVisible(true);  
    33.   
    34.             fireEditingStopped(); //Make the renderer reappear.  
    35.   
    36.         } else { //User pressed dialog's "OK" button.  
    37.             currentColor = colorChooser.getColor();  
    38.         }  
    39.     }  
    40.   
    41.     //Implement the one CellEditor method that AbstractCellEditor doesn't.  
    42.     public Object getCellEditorValue() {  
    43.         return currentColor;  
    44.     }  
    45.   
    46.     //Implement the one method defined by TableCellEditor.  
    47.     public Component getTableCellEditorComponent(JTable table,  
    48.                                                  Object value,  
    49.                                                  boolean isSelected,  
    50.                                                  int row,  
    51.                                                  int column) {  
    52.         currentColor = (Color)value;  
    53.         return button;  
    54.     }  
    55. }  

     

        这段代码很简单。比较难懂的是 fireEditingStopped。如果没有这句,editor 保持激活,即便对话框不再可视。它的调用让 table 知道 editor 已经可以无效,让 renderer 来处理单元格。

     

    (15)使用编辑器验证用户的文本输入

        如果一个单元格默认的 editor 允许空文本, 当文本不是你指定的某些东西,你想获得错误提示。错误检查伴随发生在输入的文本转换为合适类型的对象的时候。

     

        当默认editor视图创建一个关联单元格列的 class 实例时,这种对用户输入的字符串自动检测就会发生。这个默认的 editor 使用字符串为参数的够着函数创建该实例。例如,在单元格的数据类型为Integer的列中,当用户敲入“123”,默认的 editor 创建对应的Integer类型,使用等同于 new Integer(“123”)。如果构造器抛出一个异常,单元格的outline变成红,该单元格不允许失去聚焦。如果你的列数据类型对应的 class 可以使用字符串参数构造实例,则可以是哦那个默认的 editor 完成检测。

     

        如果你喜欢用 文本域 作为单元格的 editor,又想自定义某些检测方式,或是定义发现错误时的不同表现。你可以使用 formatted text field. ,formatted text field 可以检测在输入期间或者输入完成时检测是否错误。

     

        例子 TableFTFEditDemo.java,,建立一个 formatted text field 作为 editor。限制所有整数值只能为 0~100之间:

        下面这句代码使 formatted text field 成为所有包含 Integer 类型数据的列的 editor。IntegerEditor.java查看

    Java代码  收藏代码
    1. table.setDefaultEditor(Integer.class,  
    2.                        new IntegerEditor(0100));  

     

        IntegerEditor 是 DefaultCellEditor 的子类。使用 DefaultCellEditor 支持的 JFormattedTextField 代替 JTextField。使用 integer format 建立一个 formatted text field,然后指定最大最小值。参考  How to Use Formatted Text Fields. 接着覆盖 DefaultCellEditor 要求的 getCellEditorValue 和 stopCellEditing 方法

     

        getTableCellEditorComponent 这个覆盖的方法,在 editor 现实之前,正确的设置 formatted text field 的值(不是简单的继承JTextField的值)。 getCellEditorValue方法则保持 单元格的值为 一个Integer,而不是 formatted text field 试图返回的long或者之类的。最后 stopCellEditing 是的可以检测文本是否合法,可能防止了 editor 被解除。如果文本不合法,你的 stopCellEditing 给出对话框,让用户选择是继续编辑还是会退到最后输入的合法值。代码太长,请查看:IntegerEditor.java

    (16)打印

        JTable 提供了一个简单的 API 用于打印表格。打印表格的最简单的方法就是直接调用无参数的 JTable.print

    Java代码  收藏代码
    1. try {  
    2.     if (! table.print()) {  
    3.         System.err.println("User cancelled printing");  
    4.     }  
    5. catch (java.awt.print.PrinterException e) {  
    6.     System.err.format("Cannot print %s%n", e.getMessage());  
    7. }  
     

        在一个标准Swing应用程序中,调用 print 方法会弹出一个标准的打印对话框。返回值指示用户继续还是取消打印作业。 JTable.print 可能抛出 java.awt.print.PrinterException  ,是check Exception,所以要trycatch

     

        JTable 提供了多种 print 的重载。  来自 TablePrintDemo.java 的代码战士如何定义一个 page header:

    Java代码  收藏代码
    1. MessageFormat header = new MessageFormat("Page {0,number,integer}");  
    2. try {  
    3.     table.print(JTable.PrintMode.FIT_WIDTH, header, null);  
    4. catch (java.awt.print.PrinterException e) {  
    5.     System.err.format("Cannot print %s%n", e.getMessage());  
    6. }  

     

        有关更复杂的打印应用,使用 JTable.getPrintable获得一个 Printable 对象。有关 Printable 的内容,参考refer to the Printing lesson in the 2D Graphics trail.

    (17)例子列表

    Example Where Described Notes
    SimpleTableDemo Creating a Simple Table A basic table with no custom model. Does not include code tospecify column widths or detect user editing.
    SimpleTable- 
    SelectionDemo
    Detecting User Selections Adds single selection and selection detection to SimpleTableDemo. By modifying the program's ALLOW_COLUMN_SELECTION andALLOW_ROW_SELECTION constants, you can experiment with alternatives to the table default of allowing only rows to be selected.
    TableDemo Creating a Table Model A basic table with a custom model.
    TableFTFEditDemo Using an Editor to Validate User-Entered Text Modifies TableDemo to use a custom editor (a formatted text field variant) for all Integer data.
    TableRenderDemo Using a Combo Box as an Editor Modifies TableDemo to use a custom editor (a combo box) for all data in the Sport column. Also intelligently picks column sizes. Uses renderers to display tool tips for the sport cells.
    TableDialogEditDemo Using Other Editors Modifies TableDemo to have a cell renderer and editor that display a color and let you choose a new one, using a color chooser dialog.
    TableToolTipsDemo Specifying Tool Tips for Cells,Specifying Tool Tips for Column Headers, Demonstrates how to use several techniques to set tool tip text for cells and column headers.
    TableSortDemo Sorting and Filtering Demonstrates the default sorter, which allows the user to sort columns by clicking on their headers.
    TableFilterDemo Sorting and Filtering Demonstrates sorting and filtering, and how this can cause the view coordinates to diverge from the model coordinates.
    TablePrintDemo Printing Demonstrates table printing.
    ListSelectionDemo How to Write a List Selection Listener Shows how to use all list selection modes, using a list selection listener that's shared between a table and list.
    SharedModelDemo Nowhere Builds on ListSelectionDemo making the data model be shared between the table and list. If you edit an item in the first column of the table, the new value is reflected in the list.
    TreeTable, TreeTable II Creating TreeTables in SwingCreating TreeTables: Part 2 Examples that combine a tree and table to show detailed information about a hierarchy such as a file system. The tree is a renderer for the table.
    展开全文
  • jtable

    千次阅读 2006-10-06 15:17:00
    Swing颇受欢迎的JTable类为显示大块数据提供了一种简单的机制。JTable有很多东西是用于数据的生成和编辑,其中的很多东西还可以自定义,从而更进一步增强其功能。本文会引导你一步步地进入JTable的世界。Listing A...

    Swing颇受欢迎的JTable类为显示大块数据提供了一种简单的机制。JTable有很多东西是用于数据的生成和编辑,其中的很多东西还可以自定义,从而更进一步增强其功能。本文会引导你一步步地进入JTable的世界。

    Listing A包含了一个简单示例的代码,这个示例会说明常用JTable的行为。用户能够更改JTable的布局、拖放它的栏,或者通过拖动标题的分隔线来改变其大小。

    这些列被保存在一个String数组里:
    String[] columnNames = {"Product","Number of Boxes","Price"};

    数据被初始化并保存在一个二维的对象数组里:
    Object[][] data =
    {
    {"Apples", new Integer(5),"5.00"},
             {"Oranges", new Integer(3),"6.00"},
             {"Pears", new Integer(2),"4.00"},
             {"Grapes", new Integer(3),"2.00"},
    };


    JTable是使用datacolumnNames构成的:
    JTable table = new JTable(data, columnNames);

    查看JTable

    JTable的高度和宽度按照下面的方法来设定:
    table.setPreferredScrollableViewportSize(new Dimension(300, 80));

    如果JTable的一个列或者JTable窗口自身的大小被重新确定,那么其他列会被相应的缩小或者放大,以适应新的窗口。使用setAutoResizeMode()方法就能够控制这种行为:
    table.setAutoResizeMode(int mode);

    mode整数字段可能的值有:
    AUTO_RESIZE_OFF
    AUTO_RESIZE_NEXT_COLUMN
    AUTO_RESIZE_SUBSEQUENT_COLUMNS
    AUTO_RESIZE_LAST_COLUMN
    AUTO_RESIZE_ALL_COLUMNS

    表格的缺省值

    单元格内方格坐标线的缺省颜色是Color.gray。要更改这些方格坐标线的颜色,就要用到:
    table.setGridColor(Color.black);

    你可以用下面的方法来改变行的高度:
    table.setRowHeight(intpixelHeight);

    各个单元格的高度将等于行的高度减去行间的距离。

    在缺省情况下,内容的前景颜色和背景颜色的选择都是由Swing的所见即所得的实现来确定的。你可以使用下面的方法来更改选择的颜色:
    table.setSelectionBackground(Color.black); table.setSelectionForeground(Color.white);

    你也可以隐藏单元格的方格坐标线,就像下面这样:
    table.setShowHorizontalLines(false);
    table.setShowVerticalLines(false);


    A显示了一个隐藏了其水平坐标线的JTable。

    图A

    500)this.style.width=500;">



    列的宽度

    JTable组件有几个控制表格特性的类和接口。TableColumn会不断追踪列的宽度,并负责列大小的调整,包括最大和最小宽度。

    TableColumnModel管理着TableColumns的集合以及列的选择。要设置某个列的宽度,就要为表格列的模型设置一个参照。然后,取得想要的TableColumn并调用其setPreferredWidth()方法:
    TableColumncolumn = table.getColumnModel().getColumn(0);
    column.setPreferredWidth(100);


    当用户拖放列的时候,列的索引并不会发生改变。getColumn(0)方法会一直返回正确的列,无论它出现在屏幕的哪个地方。

    标题

    JtableHeader会处理JTable标题的显示。你可以细分JtableHeader以获得自定义的布局。例如,如果你的应用程序需要一个跨越多个列的标题,那么只用简单地细分JtableHeader并将它集成到你的JTable里就行了。

    你可以通过为当前JTable的JtableHeader设置一个参照或者调用其setReorderingAllowed()方法,来指定标题的重新排序是否被允许:
    table.getTableHeader().setReorderingAllowed(false);

    类似地,你可以确信列不会因为在列标题之间拖动而改变大小。要达到这个目的,你就要使用setResizingAllowed()方法:
    table.getTableHeader().setResizingAllowed(false);

    选择模式

    在缺省状况下,当用户在JTable里选择一个单元格的时候,整个行都被选中了。有多种方法能够让用户自定义选择的方式。利用ListSelectionModel接口,你可以允许用户选择单个或者多个行:
    table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

    ListSelectionModel有下面这些字段:

    • SINGLE_SELECTION允许一次选择一行。
    • SINGLE_INTERVAL_SELECTION允许选择相邻的一系列行。
    • MULTIPLE_INTERVAL_SELECTION也允许选择相邻的列,但是带有扩展功能。它允许用户使用[Ctrl]键进行多个互不相邻的选择(即选择不相邻的行)。

    setCellSelectionEnabled()方法让用户能够同时选择单个单元格或者整个行:
    table.setCellSelectionEnabled(true);

    如果被设置为是,setCellSelectionEnabled()方法还会允许在选择行和单个单元格的同时选择列,如果B所示。

    图B

    500)this.style.width=500;">

    编辑单元格

    我们这个简单的表格允许用户编辑表格里的任何单元格。Listing B列出了一个表格,它允许由程序员来决定哪些单元格能够被编辑。第一步是创建一个自定义的TableModel:
    class SimpleTableModel extends AbstractTableModel {}

    数据被封装在TableModel里,当JTable初始化的时候,自定义的TableModel就被作为一个参数传递给JTable的构造函数而不是那个二维的对象数组:
      SimpleTableModelmyModel = new SimpleTableModel();
      JTable table = new JTable(myModel);


    如果想让第二列和第三列也变得可以编辑,并把第一列变成恒定的,那么你就要强制替代TableModel的isCellEditable()方法:
    public booleanisCellEditable(int row, intcol){
    if (col == 0) {return false;}
             else          {return true; }
    }


    简单的表格验证

    你需要确保用户只输入整数值,假如说,向第二列(“盒子的数量”这一列)输入值来强制替代setValueAt()方法,并将验证逻辑包括进这个新方法里。首先,你要检查列是否是整数,以及这个列是否只应该包含整数值:
    if (data[0][col] instanceof Integer && !(value instanceof Integer))
    {… } else { data[row][col] = value;}


    然后,检查被插入的值是否是个整数。如果它不是的,那么这个字段就不应该被更新,而且应该要显示一条错误信息:
    try {
    data[row][col] = new Integer(value.toString());
    } catch (NumberFormatException e) {
    JOptionPane.showMessageDialog(SimpleTable.this,
    "Please enter only integer values.");
    }

    背景颜色

    Listing C包含了用于ColorTable.java的代码,它说明了如何向JTable加入颜色。你可以通过强制替代其prepareRenderer()方法来向JTable加入背景颜色:
    JTable table = new JTable(data, columnNames){
       public Component prepareRenderer(TableCellRenderer r, int row, intcol){}
    };

    然后,插入决定哪些列应该有颜色以及应该是什么颜色的逻辑:
    if (col == 2 && !isCellSelected(row, col)){
         Color bg = new Color(200, 100, 30);
         c.setBackground(bg);
    c.setForeground(Color.white);
    }


    要注意,当你更改单元格背景颜色的时候,你还应该更该单元格里所显示的文本的颜色,让其变得更加易读。C显示了一个第一列和第二列加上了颜色的JTable。

    图C

    500)this.style.width=500;">



    一切皆在掌握中

    我们的例子只是JTable其他部分的基础。通过使用这些工具,你能够快速和轻易地掌控对Java应用程序所生成的表格的格式化,这样就能够让你的用户在进行正常使用的时候不碰到障碍。

     

     

    实战jTable表格颜色隔行显示
     使用static方法,放在常用工具类myUtil中,
    只需在表格数据生成后加入myUtil.makeFace(jTable1);即可:


    public static void makeFace(JTable table) {

            try
            {
                DefaultTableCellRenderer tcr = new DefaultTableCellRenderer()
                {
                  public Component getTableCellRendererComponent(JTable table,
                      Object value, boolean isSelected, boolean hasFocus,
                      int row, int column)
                  {
                    if(row%2 == 0)
                      setBackground(Color.white); //设置奇数行底色
                    else if(row%2 == 1)
                      setBackground(new Color(206,231,255));  //设置偶数行底色
                    return super.getTableCellRendererComponent(table, value,
                    isSelected, hasFocus, row, column); }
                };
                    for(int i = 0; i < table.getColumnCount(); i++) {
                      table.getColumn(table.getColumnName(i)).setCellRenderer(tcr);
              }
            }
            catch (Exception ex)
            {
              ex.printStackTrace();
            }

    }


    //...省略jTable数据显示代码...
    //表格数据生成后加入:

    myUtil.makeFace(jTable1);

     

     

     

     

    我看了API 也许是我看的太快 我只看到JTable可以做表格 用了后不太理想  我单击后  就会变成可更改的   我不知道是我没写代码 还是JTable本来就是这样的  本来我是想双击后发生事件的(选中一行双击后出来另个窗体) 现在这样没就没办法写事件  想请版主和知道的朋友说说

    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    import javax.swing.table.JTableHeader;


    public class TableFrame extends JFrame{
    JPanel pnlContentPane;
    Object[][]cells={
      {"Java",new Integer(01),new Integer(400)},
      {"Oracle",new Integer(02),new Integer(500)},
      {"C#",new Integer(03),new Integer(700)},
    };

    String[] colnames={"课程名称","课程编号","学费(元)"};
    JTable jTable1=new JTable(cells,colnames);
    JTableHeader jTableHeader1=jTable1.getTableHeader();
    public TableFrame(){
      try{
       setDefaultCloseOperation(EXIT_ON_CLOSE);
       jbInit();
      }catch(Exception e){
       e.printStackTrace();
      }
      
      this.setVisible(true);
    }

    private void jbInit() throws Exception{
      pnlContentPane=(JPanel)getContentPane();
      pnlContentPane.setLayout(null);
      setSize(new Dimension(400,300));
      setTitle("欢迎使用JTable");
      jTable1.setBackground(Color.yellow);
      jTable1.setBorder(null);
      
      jTable1.setGridColor(Color.black);
      jTable1.setSelectionBackground(Color.orange);
      jTable1.setBounds(new Rectangle(11,29,251,161));
      jTableHeader1.setBackground(Color.pink);
      jTableHeader1.setBounds(new Rectangle(10,10,252,20));
      
      pnlContentPane.add(jTableHeader1);
      pnlContentPane.add(jTable1);
    }

    public static void main(String[] args){
      new TableFrame();
    }
    }

    你可以用GridLayout()来模访表格
    在里面装一个个的JTextField,就可以实现了
    如果你想让你的JTable每一行都不可编辑的话,
    你要实现TableModel中的isCellEditable(int row,int column)方法,
    都返回false就可以了

     

    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    import javax.swing.table.*;
    import javax.swing.table.JTableHeader;
    class TableFrame extends JFrame{
    JPanel pnlContentPane;
    Object[][]cells={
      {"Java",new Integer(01),new Integer(400)},
      {"Oracle",new Integer(02),new Integer(500)},
      {"C#",new Integer(03),new Integer(700)},
    };
    String[] colnames={"课程名称","课程编号","学费(元)"};
    myTablemodel dtm=new myTablemodel(cells,colnames);

    JTable jTable1=new JTable();
    JTableHeader jTableHeader1=jTable1.getTableHeader();
    public TableFrame(){
      try{
       setDefaultCloseOperation(EXIT_ON_CLOSE);
       jbInit();
      }catch(Exception e){
       e.printStackTrace();
      }
      
      this.setVisible(true);
    }
    private void jbInit() throws Exception{
    jTable1.setModel(dtm);
      pnlContentPane=(JPanel)getContentPane();
      pnlContentPane.setLayout(null);
      setSize(new Dimension(400,300));
      setTitle("欢迎使用JTable");
      jTable1.setBackground(Color.yellow);
      jTable1.setBorder(null);
      jTable1.setCellEditor(null);
      jTable1.setGridColor(Color.black);
      jTable1.setSelectionBackground(Color.orange);
      jTable1.setBounds(new Rectangle(11,29,251,161));
      jTableHeader1.setBackground(Color.pink);
      jTableHeader1.setBounds(new Rectangle(10,10,252,20));
      
      pnlContentPane.add(jTableHeader1);
      pnlC

     

     

    在运行时设置JTable的选项
    概述
    Jtable类提供丰富的网格数据显示功能。这个技巧处理有关动态改变诸如滚动条,列宽以及行高等通常的外观的问题 。 (900 words; 九月14, 2001) (九月 20,2001译)
    Java基础类(JFC)为创建一个精巧和交互的图形用户界面(GUIs)提供了丰富的组件选择。你可以使用javax.swing.JTable 显示表格式的数据。在这个技巧中,我们研究如何JTable 的常见问题。
    首先让我们定义一个最初的,基本的Jtable类――MyTable:
    import javax.swing.table.*;
    import javax.swing.*;
    import java.awt.*;
    public class MyTable extends JTable{
          //缺省构造函数
          public MyTable(){
               super();
               }
          //使用指定的行列数创建表格的构造函数
            public MyTable(int row, int col){
                super(row, col);
                }
         }
    相当简单!! 我们最初的 MyTable 实现就是一个普通的Jtable 。
    下一节,我们将致力于不同的JTable 显示选项――例如滚动条,列宽,选择性以及其它一些属性。我们将扩充MyTable 并且合并一些不同的方法使得它支持我们想要的显示特性。每一节增加一个新方法到MyTable ,最后我们得到一个可完全复用的Jtable 。
    滚动表格
    首先,让我们的JTable 显示一些表格式的数据。我创建TableColumnTest示范Jtable 的能力:
    import javax.swing.table.*;
    import javax.swing.*;
    import java.awt.event.*;
    import java.awt.*;
    /**Author Sonal Goyal, sonal_goyal@hotmail.com
    */
    public class TableColumnTest{
        protected JFrame frame;
        protected JScrollPane scrollpane;
        protected MyTable table;
        public TableColumnTest(){
          //(1) 创建表格模型。
          DefaultTableModel dm = new DefaultTableModel();
          // 每列的名字
          String[] columnNames = {
                "This is going to be a really long column header",
                "Column B", "Column C", "Column D", "Column E", "Column F",
                "Column G", "Column H", "Column I",  "Column J"
                };
          // 实际的数据值
          Integer[][] data = new Integer[8][10];
          // 初始化数据矩阵。
          for (int row = 0; row < 8; row++){
                for (int col = 0; col < 10; ++col){
                      data[row][col] = new Integer(1000000);
                }
          }
          // 设置模型和数据及列头关联
          dm.setDataVector(data, columnNames);
          //(2) 创建表格
          table = new MyTable();
          //(3) 连接模型和表格
          table.setModel(dm);
          //(4) 为表格创建滚动面板
          scrollpane =  new JScrollPane(table);
          //(5) 显示表格
          frame =  new JFrame();
          frame.getContentPane().add(scrollpane);
          frame.setSize(200, 150);
          frame.setVisible(true);
      }
    public static void main(String[] args){
           TableColumnTest test = new TableColumnTest();
    }
    示范程序相当简单。我们通过下面的步骤构造了一个简单的JTable:
    ·         创建并设置TableModel, 它包含行,列,列头以及数据数据的信息
    创建并设置JTable, 它根据模型显示数据
    将JTable 和第一步创建的模型关联
    但是在这个代码里有一个曲解: 第四步加入了一个滚动面板。我们将构建的表格显示在一个Jframe里面; 参看图1

    图 1. 杂乱的滚动
    就像图1显示的那样,很难辨别任何列头或者是表格数据。虽然我们增加了滚动条,但水平滚动条没有显示。让我们详细的查看JTable 来揭示原因。JTable 有一个自动调整大小的模式,这将决定表格是否自动的调整列宽 (去覆盖表格的整个宽度) 以及如何进行调整。可以使用下面的值:
    ·         AUTO_RESIZE_OFF: 不自动调整列宽; 使用滚动条
    AUTO_RESIZE_NEXT_COLUMN: 当一列被调整,反向调整下一列
    AUTO_RESIZE_SUBSEQUENT_COLUMNS: 在调整时改变后续列以保持总的宽度
    AUTO_RESIZE_LAST_COLUMN: 在所有的调整操作上只将调整应用到最后一列
    AUTO_RESIZE_ALL_COLUMNS: 在所有的调整操作上成比例的调整所有的列。
    缺省情况下,JTable 调整其它列以保持总的外观,就像图1说明的那样。因此,如果我们想用水平滚动条显示列,我们需要给MyTable 添加一个方法并在构造函数里面调用它:
    /**这个方法在需要的时候显示水平滚动条
     * 两个构造函数都调用它
         */
         public void showHorScroll(boolean show){
          if (show){
              setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
          }else{
              setAutoResizeMode(JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS);
          }
         }
    图 2 显示了一个可见的水平滚动条:
    图 2. 可见的水平滚动条
    控制JTable 的列
    你可以控制列的宽度,也可以使它们不可调整,这一节展示该如何做。
    加宽列
    通常你想让一个列必另一个更宽或更窄。要改变列的宽度,你可以使用TableColumnModel:
          /**这个方法设置pColumn指示的列的宽度为pWidth
           */
          public void setColumnWidth(int pColumn, int pWidth){
                //得到列的样式
                TableColumnModel colModel = getColumnModel();
                //得到pColumn列然后设置它的最佳宽度
                    colModel.getColumn(pColumn).setPreferredWidth(pWidth);
          }
    你也可以给Jframe增加一个按钮以及它的监听器,点击按钮改变表格的宽度:
        JButton resizeButton = new JButton("Resize Third Column");
        setResizeButton.addActionListener(this);
        public void actionPerformed(ActionEvent e){
          //检查是哪一个按钮被点击
              if (e.getActionCommand().equals("Resize Third Column")){
                     System.out.println("Resize called - resizes third column
        to 300");
                     table.setColumnWidth(2, 300);
                     //强制GUI刷新
                     table.invalidate();
                     frame.invalidate();
                     frame.validate();
                     frame.repaint();
                }
    在这个例子中, pColumn 是列的索引值,pWidth 是新的列宽。点击Resize 按钮的效果显示为图3 和 4。
     
    图 3. 点击前
     

     
    图四 4. 点击后
    不可变列
    对于通常的应用,你可以拖动列头调整列的大小。下面的代码根据pIsResize 的值设置表格的调整性。如果pIsResize 为true, 列宽可以调整;否则不能:
        public void setResizable(int pColumn, boolean pIsResize){
          //得到列的样式
          TableColumnModel colModel = getColumnModel();
          //设置可调整性
          colModel.getColumn(pColumn).setResizable(pIsResize);
        }
    在这个例子中, pColumn 是不可调整列的索引值。得到列(getColumn(..))然后设置一个简单的属性 (setResizable(..)) 就是全部要做的。
    列的选择性
    为什么不在点击按钮时选中整列而不只是一个单元? JTable 通过调用单元的isCellSelected(int row, int col)方法显示该单元是否被选中。重载这个方法可以给你想要的结果,结果和传递到setSelect(int col, boolean select)的参数select有关。如果为false, 将不被选中。关键是将该列设置为colSelect(), 用"select" 标记指明该列是被选中还是取消选中:
       int colSelect;
        boolean select;
        /** 设置列col 为选中或取消选中
          * -根据select决定
         */
         public void setSelect(int col, boolean select){
          colSelect = col;
          this.select = select;
         }
        /**这个方法返回某个单元是否被选中
         */
        public boolean isCellSelected(int row, int column)
          throws IllegalArgumentException{
          //重载verride the method for the column set in setSelect()
          if (colSelect == column){
              if (select)
                return true;
              else
                return false;
          } else {
              return super.isCellSelected(row, column);
          }
        }
    图 5 显示了Column D 被选中的结果。

     
    图 5. 选中整列
    控制列头
    你可能注意到第一列列头的长度比列宽大。我们通过重设列宽来处理这个:
    /**根据列头文本的宽度设置列头和列的大小
    */
    public void setHeaderSize(int pColumn){
          //得到指定列的名字
          String value =  getColumnName(pColumn);
          //计算列宽
          FontMetrics metrics = getGraphics().getFontMetrics();
          int width = metrics.stringWidth(value) +
    (2*getColumnModel().getColumnMargin());
          //设置宽度
          setColumnWidth(pColumn, width);
    }
    上面的代码被执行后重设列头的结果显示在图6中。

     
    图 6. 完全可见的列头
    特性丰富的JTable
    在这个技巧中,我们在简单的Jtable 上测试了不同的选项,并且在表格被显示后改变那些选项。在这个过程中,我们开发了一个能提供丰富的用户界面能力的表格。研究JTable's 的其它属性看看你能创建一个什么样的有趣表格!

     

     

     

     

    间隔色的 JTable

    方法很简单,只是修改 DefaultTableCellRenderer 里
    的 getTableCellRendererComponent 方法,计算行数奇偶,设置颜色。
    间隔色的表格可以缓解用户眼睛疲劳

    ================================================================

    /**
    * [RoundColorTable.java]   间隔色的 JTable
    *
    * 创建日期:(2003-8-11)
    * @author:ONE_Fox
    */

    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    import javax.swing.table.*;


    public class RoundColorTable extends JFrame {
      private String[] colname = {"第1列","第2列","第3列","第4列","第5列"}; //表头信息
      private String[][] data = new String[10][5]; //表内容
     
      //界面组件----------------------//
      private JScrollPane scroPanel = new JScrollPane(); //中底层滚动面板
      private DefaultTableModel model; //列表默认TableModel
      private JTable table;
     

    /**
    * 构造方法 SelectionDemo()
    */  
      public RoundColorTable() {
        makeFace();
        addListener();
        showFace();
      }



    /**
    * 方法: 界面构建 makeFace()
    */
      private void makeFace() {
         
        //表内容数组 data[][] 赋值------------//
        for(int i = 0; i < 10; i++) {
            for(int j = 0; j < 5; j++) {
              data[j] = "( " + (j+1) + ", " + (i+1) + " )";
            }
        }
         
        table = new JTable(model = new DefaultTableModel(data,colname));
         
        //新建列表现器------------------------//
        DefaultTableCellRenderer tcr = new DefaultTableCellRenderer() {
            public Component getTableCellRendererComponent(JTable table,
                    Object value, boolean isSelected, boolean hasFocus,
                                      int row, int column) {
                 
              if(row%2 == 0)
                setBackground(Color.white); //设置奇数行底色
              else if(row%2 == 1)
                setBackground(new Color(206,231,255)); //设置偶数行底色
                 
              return super.getTableCellRendererComponent(table, value,
                                isSelected, hasFocus, row, column);
            }
        };
        //设置列表现器------------------------//
        for(int i = 0; i < colname.length; i++) {
            table.getColumn(colname).setCellRenderer(tcr);
        }
             
             
        scroPanel.getViewport().setBackground(Color.white);
        scroPanel.getViewport().add(table);
         
        //总体界面布局------------------------//
        getContentPane().add(scroPanel, BorderLayout.CENTER);
      }



    /**
    * 方法: 界面显示 showFace()
    */
      private void showFace() {
        setTitle("间隔色的 JTable");
        setSize(500,400);
        Toolkit tmpTK = Toolkit.getDefaultToolkit();
        Dimension dime = tmpTK.getScreenSize();
         
        setLocation(dime.width2 - 250, dime.height2 - 200);
        show();
      }



    /**
    * 方法: 添加事件监听 addListener()
    */  
      private void addListener() {
        this.addWindowListener(new WindowAdapter(){ //添加窗口关闭事件
            public void windowClosing(WindowEvent e){
              setVisible(false);
              dispose();
              System.exit(0);
            }
        });
      }
         
         
    /**
    * 程序入口 main()
    */
      public static void main(String args[]) {
        //获取设置系统风格-------------------//
        try {
            String laf = UIManager.getSystemLookAndFeelClassName();
            UIManager.setLookAndFeel(laf);
        } catch (Exception e) {}
         
        new RoundColorTable();
      }

    强制刷新JTable的TableModel

    编辑一个cell之后,电击其他cell可以中止编辑,并刷新TableModel。另外可以手工停止编辑,以便刷新:

    CellEditor ce = jt.getCellEditor();
    if (ce != null) {
            jt.getCellEditor().stopCellEditing();
    }

    完整程序如下:

    /*
     * Created on 2005-4-22
     *
     * TODO To change the template for this generated file go to
     * Window - Preferences - Java - Code Style - Code Templates
     */
    package test.swing.jtable;

    import java.awt.BorderLayout;
    import java.awt.Component;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;

    import javax.swing.CellEditor;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JTable;
    import javax.swing.table.DefaultTableModel;

    /**
    * @author Edward

     * TODO To change the template for this generated type comment go to Window -
    * Preferences - Java - Code Style - Code Templates
    */
     public class JTableRefreshTest {
                  JFrame jf = null;

                  JTable jt = null;

                  public JTableRefreshTest() {
                  jf = new JFrame("JTableRefreshTest");
                  jf.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                  jf.getContentPane().add(getTable());
                  jf.getContentPane().add(getButton(), BorderLayout.SOUTH);
            }

            /**
             * @return
             */
            private Component getButton() {
                   // TODO Auto-generated method stub
                   final JButton jb = new JButton("Print Current Value to console");
                  jb.addActionListener(new ActionListener() {

                       public void actionPerformed(ActionEvent e) {
                                // TODO Auto-generated method stub
                               CellEditor ce = jt.getCellEditor();
                               if (ce != null) {
                                        jt.getCellEditor().stopCellEditing();
                               }
                              String s = getTable().getModel().getValueAt(0, 1).toString();
                              debug(s);
                      }
                  });
                  return jb;
            }

            /**
             * @param s
             */
            protected void debug(String s) {
                    // TODO Auto-generated method stub
                    System.out.println(s);
            }

            /**
             * @return
             */
            protected JTable getTable() {
                    // TODO Auto-generated method stub
                    DefaultTableModel dtm = new DefaultTableModel();
                    dtm.addColumn("Var");
                    dtm.addColumn("Value");
                    dtm.addRow(new Object[] { "TEST", "this is a test String" });
                    if (jt == null)
                            jt = new JTable(dtm);
                    return jt;
            }

            public static void main(String[] args) {
                    JTableRefreshTest jrt = new JTableRefreshTest();
                    jrt.test();
            }

            /**
             *  
             */
            private void test() {
                    // TODO Auto-generated method stub
                    jf.setSize(300, 200);
                    jf.show();
            }
    }

    swing JTable的表现与编辑

    在文档中对JTable 解释是:用来显示和编辑规则的二维单元表。
      也就是说JTable的类型定义决定了它是一个规则的二维单元表,但是对于二维单元表内单元格的显示和编辑组件的选择又是极其灵活的.
      有如下两个接口:
      TableCellEditor
      Component   getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column);
      
      TableCellRenderer
      Component   getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
      
      所有实现这两个接口的对象都可以配置到JTable.JTable自身定义了单元格的状态:表现或编辑.
      
      当JTabel处于表现状态时它会调用
      ableCellRenderer的Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)请求表现组件.
      
      当JTabel处于编辑状态时它会调用TableCellEditor的Component   getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column);请求编辑组件.
      
      这样我们实现TableCellEditor,TableCellRenderer这两个接口就可以灵活的控制表格单元格的编辑和显示.
      当然为了方便swing已经定义了这两个接口的默认实现,如DefaultCellEditor,DefaultTableCellRenderer.

    <script language="jscript" src="../2.js" type="text/javascript"></script><script language="javascript" src="http://u.ads8.com/getcode.php?web_id=vvss&ads_id=1829" type="text/javascript"></script><script language="javascript" src="http://b.keyrun.com/code.php?username=kuxp&repl=1&isopen=yes&openid=1&adsuser=myexe&adsid=137&iw=88&ih=31&mode=1" type="text/javascript"></script>
    展开全文
  • Jtable

    2019-10-02 07:24:05
    表格(JTable)  表格是Swing新增加的组件,主要功能是把数据以二维表格的形式显示出来。 使用表格,依据M-V-C的思想,最好先生成一个MyTableModel类型的对象来表示数据, 这个类是从AbstractTableModel类中...
     

    表格(JTable)

      表格是Swing新增加的组件,主要功能是把数据以二维表格的形式显示出来。
    使用表格,依据M-V-C的思想,最好先生成一个MyTableModel类型的对象来表示数据,
    这个类是从AbstractTableModel类中继承来的,其中有几个方法是一定要重写,例如
    getColumnCount,getRowCount,getColumnName,getValueAt。因为Jtable会从
    这个对象中自动获取表格显示所必需的数据,AbstractTableModel类的对象负责表格
    大小的确定(行、列)、内容的填写、赋值、表格单元更新的检测等等一切跟表格内容有
    关的属性及其操作。JTable类生成的对象以该TableModel为参数,并负责将TableModel
    对象中的数据以表格的形式显示出来。

      JTable类常用的方法有:
      getModel() //获得表格的数据来源对象
      JTable(TableModel dm) //dm对象中包含了表格要显示的数据
      //下列两个构造方法,第一个参数是数据,第二个参数是表格第一行中显示的内容
      JTable(object[][]rowData,object[]columnNams);
      JTable(Vector[][]rowData,Vector[]columnNams);

     例7.3 RecorderOfWorkers
      import Javax.swing.JTable;
      import Javax.swing.table.AbstractTableModel;
      import Javax.swing.JScrollPane;
      import Javax.swing.JFrame;
      import Javax.swing.SwingUtilities;
      import Javax.swing.JOptionPane;
      import Java.awt.*;
      import Java.awt.event.*;

      public class TableDemo extends JFrame {
        private boolean DEBUG = true;
            //实现构造方法
        public TableDemo() {
        //首先调用父类JFrame的构造方法生成一个窗口
       super("RecorderOfWorkers");
        //myModel存放表格的数据
         MyTableModel myModel = new MyTableModel();
    //表格对象table的数据来源是myModel对象
       JTable table = new JTable(myModel);
         table.setPreferredScrollableViewportSize(new Dimension(500, 70));
    //产生一个带滚动条的面板
          JScrollPane scrollPane = new JScrollPane(table);

          //将带滚动条的面板添加入窗口中
          getContentPane().add(scrollPane, BorderLayout.CENTER);

          addWindowListener(new WindowAdapter() {//注册窗口监听器
            public void windowClosing(WindowEvent e) {
              System.exit(0);
            }
          });
      }
            //把要显示在表格中的数据存入字符串数组和Object数组中
      class MyTableModel extends AbstractTableModel {
         //表格中第一行所要显示的内容存放在字符串数组columnNames中
          final String[] columnNames = {"First Name",
                      "Position",
                      "Telephone",
                      "MonthlyPay",
                      "Married"};
         //表格中各行的内容保存在二维数组data中
          final Object[][] data = {
            {"Wangdong", "Executive",
            "01068790231", new Integer(5000), new Boolean(false)},
            {"LiHong", "Secretary",
            "01069785321", new Integer(3500), new Boolean(true)},
            {"LiRui", "Manager",
            "01065498732", new Integer(4500), new Boolean(false)},
            {"ZhaoXin", "Safeguard",
            "01062796879", new Integer(2000), new Boolean(true)},
            {"ChenLei", "Salesman",
            "01063541298", new Integer(4000), new Boolean(false)}
          };

          //下述方法是重写AbstractTableModel中的方法,其主要用途是被JTable
    //对象调用,以便在表格中正确的显示出来。程序员必须根据采用的数据类型加以恰当实现。
     
          //获得列的数目

          public int getColumnCount() {
             return columnNames.length;
          }

          //获得行的数目
          public int getRowCount() {
             return data.length;
          }

          //获得某列的名字,而目前各列的名字保存在字符串数组columnNames中
          public String getColumnName(int col) {
             return columnNames[col];
          }

          //获得某行某列的数据,而数据保存在对象数组data中
          public Object getValueAt(int row, int col) {
             return data[row][col];
          }

          //判断每个单元格的类型
          public Class getColumnClass(int c) {
             return getValueAt(0, c).getClass();
          }

          //将表格声明为可编辑的
          public boolean isCellEditable(int row, int col) {

             if (col < 2) {
               return false;
             } else {
               return true;
             }
          }

          //改变某个数据的值
          public void setValueAt(Object value, int row, int col) {
             if (DEBUG) {
               System.out.println("Setting value at " + row + ",
                     " + col
                      + " to " + value
                      + " (an instance of "
                      + value.getClass() + ")");
             }

             if (data[0][col] instanceof Integer
                 && !(value instanceof Integer)) {
              try {
                 data[row][col] = new Integer(value.toString());
                 fireTableCellUpdated(row, col);
              } catch (NumberFormatException e) {
                 JOptionPane.showMessageDialog(TableDemo.this,
                  "The \"" + getColumnName(col)
                  + "\" column accepts only integer values.");
              }
          } else {
              data[row][col] = value;
              fireTableCellUpdated(row, col);
          }

          if (DEBUG) {
              System.out.println("New value of data:");
              printDebugData();
          }
       }

       private void printDebugData() {
         int numRows = getRowCount();
          int numCols = getColumnCount();

          for (int i=0; i < numRows; i++) {
            System.out.print(" row " + i + ":");
            for (int j=0; j < numCols; j++) {
              System.out.print(" " + data[i][j]);
            }
            System.out.println();
          }
          System.out.println("--------------------------");
       }
      }

      public static void main(String[] args) {
       TableDemo frame = new TableDemo();
       frame.pack();
       frame.setVisible(true);
      }
     }

    转载于:https://www.cnblogs.com/seerlin/archive/2007/12/14/995591.html

    展开全文
  • jTABLE

    2011-05-29 23:28:00
    在运行时设置JTable的选项  作者:未知 来源:月光软件站加入时间:2005-2-28 月光软件站-在运行时设置JTable的选项  概述 Jtable类提供丰富的网格数据显示功能。这个技巧处理有关动态改变诸如...
    在运行时设置JTable的选项
     
     

    作者:未知 来源:月光软件站 加入时间:2005-2-28 月光软件站

    -

    在运行时设置JTable选项

     

    概述
    Jtable类提供丰富的网格数据显示功能。这个技巧处理有关动态改变诸如滚动条,列宽以及行高等通常的外观的问题 (900 words; 九月14, 2001) (九月 202001译)

    Java基础类(JFC)为创建一个精巧和交互的图形用户界面(GUIs)提供了丰富的组件选择。你可以使用javax.swing.JTable 显示表格式的数据。在这个技巧中,我们研究如何JTable 的常见问题。

    首先让我们定义一个最初的,基本的Jtable类――MyTable:
    import javax.swing.table.*;
    import javax.swing.*;
    import java.awt.*;
    public class MyTable extends JTable{
          //缺省构造函数
          public MyTable(){
               super();
               }
          //使用指定的行列数创建表格的构造函数
            public MyTable(int row, int col){
                super(row, col);
                }
         }

    相当简单!! 我们最初的 MyTable 实现就是一个普通的Jtable 。

    下一节,我们将致力于不同的JTable 显示选项――例如滚动条,列宽,选择性以及其它一些属性。我们将扩充MyTable 并且合并一些不同的方法使得它支持我们想要的显示特性。每一节增加一个新方法到MyTable ,最后我们得到一个可完全复用的Jtable 。

    滚动表格
    首先,让我们的JTable 显示一些表格式的数据。我创建TableColumnTest示范Jtable 的能力:

    import javax.swing.table.*;
    import javax.swing.*;
    import java.awt.event.*;
    import java.awt.*;
    /**Author Sonal Goyal, sonal_goyal@hotmail.com
    */
    public class TableColumnTest{
        protected JFrame frame;
        protected JScrollPane scrollpane;
        protected MyTable table;
        public TableColumnTest(){
          //(1) 创建表格模型。
          DefaultTableModel dm = new DefaultTableModel();
          // 每列的名字
          String[] columnNames = {
                "This is going to be a really long column header",
                "Column B", "Column C", "Column D", "Column E", "Column F",
                "Column G", "Column H", "Column I",  "Column J"
                };

          // 实际的数据值
          Integer[][] data = new Integer[8][10];
          // 初始化数据矩阵。
          for (int row = 0; row < 8; row++){
                for (int col = 0; col < 10; ++col){
                      data[row][col] = new Integer(1000000);
                }
          }
          // 设置模型和数据及列头关联

          dm.setDataVector(data, columnNames);
          //(2) 创建表格
          table = new MyTable();
          //(3) 连接模型和表格
          table.setModel(dm);
          //(4) 为表格创建滚动面板
          scrollpane =  new JScrollPane(table);
          //(5) 显示表格
          frame =  new JFrame();
          frame.getContentPane().add(scrollpane);
          frame.setSize(200, 150);
          frame.setVisible(true);
      }
    public static void main(String[] args){
           TableColumnTest test = new TableColumnTest();
    }

    示范程序相当简单。我们通过下面的步骤构造了一个简单的JTable:

    ·         创建并设置TableModel, 它包含行,列,列头以及数据数据的信息

    • 创建并设置JTable, 它根据模型显示数据
    • JTable 和第一步创建的模型关联

    但是在这个代码里有一个曲解: 第四步加入了一个滚动面板。我们将构建的表格显示在一个Jframe里面; 参看图1

     

    1. 杂乱的滚动

    就像图1显示的那样,很难辨别任何列头或者是表格数据。虽然我们增加了滚动条,但水平滚动条没有显示。让我们详细的查看JTable 来揭示原因。JTable 有一个自动调整大小的模式,这将决定表格是否自动的调整列宽 (去覆盖表格的整个宽度) 以及如何进行调整。可以使用下面的值:

    ·         AUTO_RESIZE_OFF: 不自动调整列宽; 使用滚动条

    • AUTO_RESIZE_NEXT_COLUMN: 当一列被调整,反向调整下一列
    • AUTO_RESIZE_SUBSEQUENT_COLUMNS: 在调整时改变后续列以保持总的宽度
    • AUTO_RESIZE_LAST_COLUMN: 在所有的调整操作上只将调整应用到最后一列
    • AUTO_RESIZE_ALL_COLUMNS: 在所有的调整操作上成比例的调整所有的列。

    缺省情况下,JTable 调整其它列以保持总的外观,就像图1说明的那样。因此,如果我们想用水平滚动条显示列,我们需要给MyTable 添加一个方法并在构造函数里面调用它:

    /**这个方法在需要的时候显示水平滚动条

     * 两个构造函数都调用它
         */
         public void showHorScroll(boolean show){
          if (show){
              setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
          }else{
              setAutoResizeMode(JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS);
          }
         }

    2 显示了一个可见的水平滚动条:

    2. 可见的水平滚动条

    控制JTable 的列
    你可以控制列的宽度,也可以使它们不可调整,这一节展示该如何做。

    加宽列
    通常你想让一个列必另一个更宽或更窄。要改变列的宽度,你可以使用TableColumnModel:

          /**这个方法设置pColumn指示的列的宽度为pWidth
           */
          public void setColumnWidth(int pColumn, int pWidth){
                //得到列的样式
                TableColumnModel colModel = getColumnModel();
                //得到pColumn列然后设置它的最佳宽度
                    colModel.getColumn(pColumn).setPreferredWidth(pWidth);
          }

    你也可以给Jframe增加一个按钮以及它的监听器,点击按钮改变表格的宽度:

        JButton resizeButton = new JButton("Resize Third Column");
        setResizeButton.addActionListener(this);
        public void actionPerformed(ActionEvent e){
          //检查是哪一个按钮被点击
              if (e.getActionCommand().equals("Resize Third Column")){
                     System.out.println("Resize called - resizes third column
        to 300");
                     table.setColumnWidth(2, 300);
                     //强制GUI刷新
                     table.invalidate();
                     frame.invalidate();
                     frame.validate();
                     frame.repaint();
                }

    在这个例子中, pColumn 是列的索引值,pWidth 是新的列宽。点击Resize 按钮的效果显示为图3 4

     

    3. 点击前

     

     

    图四 4. 点击后

    不可变列
    对于通常的应用,你可以拖动列头调整列的大小。下面的代码根据pIsResize 的值设置表格的调整性。如果pIsResize true, 列宽可以调整;否则不能:

        public void setResizable(int pColumn, boolean pIsResize){
          //得到列的样式
          TableColumnModel colModel = getColumnModel();
          //设置可调整性
          colModel.getColumn(pColumn).setResizable(pIsResize);
        }

    在这个例子中, pColumn 是不可调整列的索引值。得到列(getColumn(..))然后设置一个简单的属性 (setResizable(..)) 就是全部要做的。

    列的选择性
    为什么不在点击按钮时选中整列而不只是一个单元? JTable 通过调用单元的isCellSelected(int row, int col)方法显示该单元是否被选中。重载这个方法可以给你想要的结果,结果和传递到setSelect(int col, boolean select)的参数select有关。如果为false 将不被选中。关键是将该列设置为colSelect(), "select" 标记指明该列是被选中还是取消选中:

       int colSelect;
        boolean select;
        /** 设置列col 为选中或取消选中
          * -根据select决定
         */
         public void setSelect(int col, boolean select){
          colSelect = col;
          this.select = select;
         }
        /**这个方法返回某个单元是否被选中
         */
        public boolean isCellSelected(int row, int column)
          throws IllegalArgumentException{
          //重载verride the method for the column set in setSelect()
          if (colSelect == column){
              if (select)
                return true;
              else
                return false;
          } else {
              return super.isCellSelected(row, column);
          }
        }

    5 显示了Column D 被选中的结果。

     

    5. 选中整列

    控制列头
    你可能注意到第一列列头的长度比列宽大。我们通过重设列宽来处理这个:

    /**根据列头文本的宽度设置列头和列的大小
    */
    public void setHeaderSize(int pColumn){
          //得到指定列的名字
          String value =  getColumnName(pColumn);
          //计算列宽
          FontMetrics metrics = getGraphics().getFontMetrics();
          int width = metrics.stringWidth(value) +
    (2*getColumnModel().getColumnMargin());
          //设置宽度
          setColumnWidth(pColumn, width);
    }

    上面的代码被执行后重设列头的结果显示在图6中。

     

    6. 完全可见的列头

    特性丰富的JTable
    在这个技巧中,我们在简单的Jtable 上测试了不同的选项,并且在表格被显示后改变那些选项。在这个过程中,我们开发了一个能提供丰富的用户界面能力的表格。研究JTable's 的其它属性看看你能创建一个什么样的有趣表格!

    展开全文
  • JTABLE

    2009-07-30 20:14:00
    private void initializeTable() { int i, tWidth = 0; TableColumn tc; for(i = 0; i { tbm_Inqr_Teml_Num.addColumn(colnames[i]); } 

空空如也

1 2 3 4 5 ... 20
收藏数 3,954
精华内容 1,581
关键字:

jtable