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是使用data和columnNames构成的:
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应用程序所生成的表格的格式化,这样就能够让你的用户在进行正常使用的时候不碰到障碍。
只需在表格数据生成后加入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 的其它属性看看你能创建一个什么样的有趣表格!
方法很简单,只是修改 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(); |
完整程序如下:
/* import java.awt.BorderLayout; import javax.swing.CellEditor; /** JTable jt = null; public JTableRefreshTest() { /** public void actionPerformed(ActionEvent e) { /** /** public static void main(String[] args) { /** |
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.