总结:
TableModel的作用
- 决定某个单元格是否可以编辑
- 决定每一列的数据的类型
- 实际存储JTable中的数据
- 定义如何对JTable中的数据进行操作的方法
TableColumnModel的作用
- 管理着所有的TableColumn的实例
- 控制着列在JTable GUI上的显示顺序;JTable是如何被选择的,而且为了控制JTable的选择它还维护了一个ListSelectionModel; margin size
TableColumn的作用
- 代表了TableModel中的数据的一个单独列
- 就是数据在JTable GUI上实际的数据显示
- 每个TableColumn都有四个东西 cell renderer、 table header renderer、cell editor和一个table header。 而每个列之所以可以改变宽度以及可以改变显示的位置就是由于我们可以操纵这个TableColumn的table header
18.17 表格
18.17.1 JTable
表格组件提供了以 行、列 的形式显示数据的视图。 在程序开发中是一个非常重要的组件。 尤其在需要将一堆数据有条理地展现给用户时,表格设计更能显示出它的重要性
在Swing中可以通过JTable组件非常轻松地构造出所需要的表格,并且也提供了一些方法来管理这些表格的内容。
JTable类的常用方法如下所示:
范例:建立表格
package org.forfan06.jtabledemo;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
public class JTableDemo01{
public static void main(String args[]){
JFrame jframe = new JFrame("Welcome page");
String[] titles = {"姓名", "年龄", "性别", "数学成绩", "英语成绩", "总分", "是否及格"}; //定义数组表示表格的标题
Object[][] userInfo = {{"forfan06", 29, "Male", 72, 59, 131, false}, {"Linda", 27, "Female", 89, 93, 182, true}}; //定义二维对象数组
JTable table = new JTable(userInfo, titles); //实例化JTable组件对象
JScrollPane scr = new JScrollPane(table); //加入滚动条
jframe.add(scr);
jframe.setSize(370, 90);
jframe.setVisible(true);
jframe.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(1);
}
});
}
}
上面程序,使用一个二维数组表示表格中的数据,表格中的数据按照标题栏设置的顺序进行排列,之后将表格加入到一个滚动框中,再将滚动框加入到面板中。
===============================================================================================================
JTable使用时要加入到JScrollPane中。
在使用JTable时,如果不把JTable加入到JScrollPane中,则表格的标题将无法显示!!!!!!!!!!
===============================================================================================================
18.17.2 使用TableModel构建表格
使用JTable构建的表格相对比较单一,如果想制作一些操作界面更加友好的表格,例如,在表格上加入一些单选按钮或下拉列表框,则需要借助于TableModel接口了。
在TableModel接口中定义了许多与表格操作相关的方法,如下所示:
但是,在实际的开发中很少直接实现以上的接口,而都是使用其接口的子类AbstractTableModel和DefaultTableModel。 但是不管使用哪个子类实现,首先都必须了解TableColumnModel接口。
TableColumnModel接口定义了许多与表格的行、列有关的方法。例如,增加行(列)、删除行(列),设置和取得表格元素的信息等操作。。。通常用户不会直接实现TableColumModel接口,而是直接通过JTable中的getColumnModel()方法取得TableColumnModel的实例!!!!!
TableColumnModel接口中定义的方法如下所示:
在TableColumnModel接口的操作中,增加或者删除都是以TableColumn类的形式出现的。 TableColumn类表示每一列的数据!!!!!!!
下面就先使用AbstractTableModel类建立一个表格。建立一个DefaultTable类直接集成AbstractTableModel类,然后覆写相应的抽象方法即可。
范例:使用AbstractTableModel构建表格
package org.forfan06.jtabledemo;
import java.awt.BorderLayout;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.DefaultCellEditor;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
class DefaultTable extends AbstractTableModel{
private String[] titles = {"姓名", "年龄", "性别", "数学成绩", "英语成绩", "总分", "是否及格"}; //定义数组表示表格的标题
private Object[][] userInfo = {{"forfan06", 29, "Male", 72, 59, 131, false}, {"Linda", 27, "Female", 89, 93, 182, true}}; //定义二维对象数组
public int getColumnCount(){
return this.titles.length;
}
public int getRowCount(){
return this.userInfo.length;
}
public Object getValueAt(int row, int column){
return this.userInfo[row][column];
}
//得到列的名字,如果不覆些此方法,则以后无法显示列的名称
public String getColumnName(int column){
return this.titles[column];
}
/*
*返回列的类型,如果不覆写此方法,则无法按格式显示数据,格式如下:
*1、 boolean类型,以CheckBox方式显示
*2、 数值类型: 以JLabel显示,文字向右排列
*/
public Class<?> getColumnClass(int column){
return this.getValueAt(0, column).getClass(); //取得指定列的类型
}
//如果不覆写此方法,则表格无法编辑
public boolean isCellEditable(int row, int column){
return true; //所有单元格均可编辑
}
public void setValueAt(Object newValue, int row, int column){
this.userInfo[row][column] = newValue;
}
}
class TableColumnModelDemo{
private JFrame jframe = new JFrame("Welcome page");
private JTable table = null; //声明JTable表格对象
private DefaultTable defaultTable = new DefaultTable();
private JComboBox sexList = new JComboBox(); //定义下拉列表框
public TableColumnModelDemo(){
this.table = new JTable(this.defaultTable); //实例化JTable对象
this.sexList.addItem("Male");
this.sexList.addItem("Femal");
//下面这条语句涉及到的类和接口
/*
*Class JTable
***public TableColumnModel getColumnModel();
*
*Interface TableColumnModel
*
*Class DefaultTableColumnModel implements TableColumnModel...
***public TableColumn getColumn(int columnIndex);
*
*Class TableColumn
***public void setCellEditor(TableCellEditor cellEditor);
*
*Interface TableCellEditor
***public interface TableCellEditor extends CelLEditor
*
*Class DefaultCellEditor extends AbstractCellEditor implements TableCellEditor, TreeCellEditor... Contstructors as below:
***public DefaultCellEditor(JComboBox comboBox);
***public DefaultCellEditor(JCheckBox checkBox);
***public DefaultCellEditor(JTextField textField);
*/
this.table.getColumnModel().getColumn(2).setCellEditor(new DefaultCellEditor(this.sexList)); //将下拉列表选项加入到表格
JScrollPane scr = new JScrollPane(this.table);
JPanel toolBar = new JPanel();
this.jframe.add(toolBar, BorderLayout.NORTH);
this.jframe.add(scr, BorderLayout.CENTER);
this.jframe.setSize(370, 160);
this.jframe.setVisible(true);
this.jframe.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(1);
}
});
}
}
public class JTableDemo02{
public static void main(String args[]){
new TableColumnModelDemo();
}
}
程序运行后,可以发现: 表格中的数据都是按照指定格式进行显示的;而且因为在DefaultTable类中覆写了isCellEditable()方法,所以表格的每一项都是可编辑的;对于性别的选项使用了一个下拉列表框的形式进行了显示;在“是否及格”列上,使用了一个CheckBox来代替了原有的true和false。
=================================================================================================
以下内容来之 http://www.cnblogs.com/renyuan/archive/2012/10/15/2724541.html
http://www.cnblogs.com/langtianya/archive/2012/09/04/2671173.html
http://mxdxm.iteye.com/blog/653023
http://blog.csdn.net/tsaid/article/details/7962798
Question:表格如何绘制它的单元格呢???? (编辑器和渲染器Editors、 Renderers的概念)
Answer: 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 -- 复选框 Checkbox
- Number -- 居右的label
- Double、Float -- 类似Number,不过 从对象到文本的转化通过NumberFormat的实例来执行
- Data -- label, 对象 到 文本 的转换通过 DataFormat的实例来执行
- ImageIcon、Icom -- 居中的label
- Object -- 展示了对象的字符串值的label
单元格编辑器使用类似的法则。
注意,如果让table自己创建它的model,它会把Object作为Object各列的类型。为了指定更明确列类型。 table model一定要定义适当的getColumnClass()方法。
记住,尽管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 event on a column header... Register the appropriate of mouse listener on the table's JTableHeader object.
To detect other events... Register the appropriate listener on the JTable object.
=================================================================================================
使用AbstractTableModel类可以方便地构建表格,而使用其子类DefaultTableModel则可以对表格进行动态的操作。 例如:增加行(列)、删除行(列)等。
在DefaultTableModel类中提供了以下的常用操作方法:
范例:动态操作表格
package org.forfan06.jtabledemo;
import java.awt.BorderLayout;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
class ChangeTable implements ActionListener{ //实现事件监听
private JFrame jframe = new JFrame("Dynamic edit Table");
private JTable table = null; //声明JTable对象
private DefaultTableModel tableModel = null; //声明DefaultTableModel对象
private String[] titles = {"姓名", "年龄", "性别", "数学成绩", "英语成绩", "总分", "是否及格"}; //定义数组表示表格的标题
private Object[][] userInfo = {{"forfan06", 29, "Male", 72, 59, 131, false}, {"Linda", 27, "Female", 89, 93, 182, true}}; //定义二维对象数组
private JButton addRowBtn = new JButton("增加行");
private JButton removeRowBtn = new JButton("删除行");
private JButton addColBtn = new JButton("增加列");
private JButton removeColBtn = new JButton("删除列");
public ChangeTable(){ //通过构造方法完成显示的功能
//实例化DefaultTableModel对象,显示内容
this.tableModel = new DefaultTableModel(this.userInfo, this.titles); //DefaultTableModel Constructor: DefaultTableMode(Object[][] data, Object[] columnName)
this.table = new JTable(this.tableModel); //根据TableModel显示内容
JScrollPane scr = new JScrollPane(this.table); //加入滚动条
JPanel toolBar = new JPanel();
toolBar.add(this.addRowBtn);
toolBar.add(this.removeRowBtn);
toolBar.add(addColBtn);
toolBar.add(this.removeColBtn);
this.jframe.add(toolBar, BorderLayout.NORTH);
this.jframe.add(scr, BorderLayout.CENTER);
this.jframe.setSize(370, 160);
this.jframe.setVisible(true);
this.addRowBtn.addActionListener(this);
this.removeRowBtn.addActionListener(this);
this.addColBtn.addActionListener(this);
this.removeColBtn.addActionListener(this);
this.jframe.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(1);
}
});
}
public void actionPerformed(ActionEvent e){
if(e.getSource() == this.addColBtn){
this.tableModel.addColumn("新增列");
}
if(e.getSource() == this.addRowBtn){
this.tableModel.addRow(new Object[] {});
}
if(e.getSource() == this.removeColBtn){
int colCount = this.tableModel.getColumnCount(); //得到最后一列
if(colCount >= 0){ //判断是否还有列
//取得TableModel实例,以方便删除列
TableColumnModel columnMode = this.table.getColumnModel();
//取得删除列的对象,根据列的编号取得TableColumn对象
TableColumn tableColumn = columnMode.getColumn(colCount);
columnMode.removeColumn(tableColumn);
//修改表格的列数,如果不修改则在下次删除列时将出现数组越界异常
this.tableModel.setColumnCount(colCount);
}
}
if(e.getSource() == this.removeRowBtn){
int rowCount = this.tableModel.getRowCount() - 1; //得到最后一行
if(rowCount >= 0){ //判断是否还有行
this.tableModel.removeRow(rowCount);
this.tableModel.setRowCount(rowCount);
}
}
}
}
public class JTableDemo03{
public static void main(String args[]){
new ChangeTable();
}
}
在上面程序中,使用DefaultTableModel可以方便地实现增加行(列)、删除行(列)的各种操作。在删除行前先取得最后一行的编号,之后通过removeRow()方法根据行号删除掉指定行,但是在行删除之后一定要使用setRowCount()方法重新设置行数,这样在下面操作时就不会出现数据越界的异常信息。
18.18 本章要点
- Swing是在AWT基础上的一种扩展应用,提供了一套轻量级的操作组件
- 在Swing中所有的组件都是以字母J开头的,所有的组件都是继承自Component类
- JFrame是Swing提供的一个标准容器,可以向该容器上加入各个组件
- JLabel是一个标签组件,用于显示基本信息
- JButton是一个按钮组件,如果要构建不弹起的按钮则要使用JToggleButton
- 在图形界面中主要提供了FlowLayout、BorderLayout、GridLayout、CardLayout、绝对定位5种布局管理器
- 可以使用JTextField完成一个文本框,使用JPasswordField完成一个密码框,使用JTextArea完成一个文本域
- 事件发生时会产生事件源并找到对应的监听程序进行处理,在图形界面中提供了多个Listener接口进行事件的处理
- 在使用JRadioButton完成单选操作时,需要将多个JRadioButton加入到ButtonGroup中,才能实现单选的功能
- JComboBox可以完成下拉列表框的操作,使用JList可以完成列表框的显示
- 要完成菜单显示,需要将多个JMenu加入到JMenuBar中,菜单中的菜单项使用JMenuItem处理,每一个JMenuItem都表示了一个特殊的按钮
- JFileChooser可以完成文件选择的对话框
- 如果要显示一组数据,则可以使用表格的形式进行显示
18.19 习题
- 编写程序,在文本框中输入一个浮点型华氏温度,根据下面的公式将其转化成摄氏温度值并输出: 摄氏温度 = (华氏 - 32) *5/9
- 改善登陆程序,使之可以完成基于数据库的登陆操作。数据库表由用户自行设计
- 定义一张数据库表,其中包含编号(自动增长)、姓名、年龄、生日、学校,并将全部的信息通过JTable显示在图形界面中
- 编写程序,在文本框中输入英文字母,再根据“大写字母按钮”或“小写字母按钮”将输入的内容进行转换,并将转换后的结果显示在标签上
- 模仿Windows的记事本(notepad.exe)程序完成以下要求: (1) 文件的打开和保存 (2) 设置显示字体的大小
- 模仿Windows计算器程序完成一个可以用于执行+、-、*、/ 的操作。