Swing颇受欢迎的JTable类为显示大块数据提供了一种简单的机制。JTable有很多东西是用于数据的生成和编辑,其中的很多东西还可以自定义,从而更进一步增强其功能。本文会引导你一步步地进入JTable的世界。 6 M& s+ z. t2 Z: ^! V) g6 r3 i% t
Listing A包含了一个简单示例的代码,这个示例会说明常用JTable的行为。用户能够更改JTable的布局、拖放它的栏,或者通过拖动标题的分隔线来改变其大小。 ; ~3 ~8 A Z0 h' G8 M
这些列被保存在一个String数组里
1 {; J3 ~7 u7 X3 B String[] columnNames = {"Product","Number of Boxes","Price"};
" j7 n# J* M2 e F' Y+ d* @ 数据被初始化并保存在一个二维的对象数组里
- C+ q1 b+ L! L5 n0 r! L Object[][] data =
# [9 D4 c& s8 a" c { , Q4 [* L( [2 i: r. X
{"Apples", new Integer(5),"5.00"},
. R# L& N, d+ w c# O {"Oranges", new Integer(3),"6.00"}, " s5 X7 N! |* N9 l
{"Pears", new Integer(2),"4.00"},
7 P/ J1 y$ Y: d8 }$ i {"Grapes", new Integer(3),"2.00"}, # y( A1 p- V$ z
}; ' r$ T' M/ X3 G2 F$ B
JTable是使用data和columnNames构成的
9 }% T6 s" F! g* c JTable table = new JTable(data, columnNames);
9 S: T) A1 m' s) Q 查看JTable
( ]6 i3 b6 |9 ]! `; r( L JTable的高度和宽度按照下面的方法来设定
3 |+ A8 Y/ p: P* f; j$ [( X table.setPreferredScrollableViewportSize(new Dimension(300, 80)); 6 \7 x, \! x4 i; q) d% `
如果JTable的一个列或者JTable窗口自身的大小被重新确定,那么其他列会被相应的缩小或者放大,以适应新的窗口。使用setAutoResizeMode()方法就能够控制这种行为
# ]# W5 f5 `' t) ^ table.setAutoResizeMode(int mode); 4 j; n0 P4 h6 `( l
mode整数字段可能的值有 9 n; _4 W4 m! u" t8 N; b$ T
AUTO_RESIZE_OFF r3 \; Z n% N8 f% X A! N
AUTO_RESIZE_NEXT_COLUMN
5 g& h6 E V- a* h; G AUTO_RESIZE_SUBSEQUENT_COLUMNS " ?+ v9 G, L( i8 h9 M) m1 Z, z6 C
AUTO_RESIZE_LAST_COLUMN - g E/ ?/ g' E
AUTO_RESIZE_ALL_COLUMNS ) T1 K" [( X6 I# k% I1 U# G
表格的缺省值 & A: d1 |: C" G, c6 N
单元格内方格坐标线的缺省颜色是Color.gray。要更改这些方格坐标线的颜色,就要用到 ) b P7 ]4 v) w1 R
table.setGridColor(Color.black); . I2 A# H) b' M
你可以用下面的方法来改变行的高度 2 W; b( A- P3 z, Y% T1 E
table.setRowHeight(intpixelHeight);
% X8 }3 @: P. m' B& p( ]# F 各个单元格的高度将等于行的高度减去行间的距离。
2 i% S' Y1 m2 ~4 i/ U1 w1 ?) ? 在缺省情况下,内容的前景颜色和背景颜色的选择都是由Swing的所见即所得的实现来确定的。你可以使用下面的方法来更改选择的颜色
. U" _2 `3 y# a% B table.setSelectionBackground(Color.black); table.setSelectionForeground(Color.white); " u& ~# F) S! Y& d
你也可以隐藏单元格的方格坐标线,就像下面这样 $ ^$ x7 w0 p! T$ b3 t: p8 H& L8 {
table.setShowHorizontalLines(false); # M6 f7 R9 @7 B7 p$ z e
table.setShowVerticalLines(false); 4 [6 I+ a: Z7 ~
列的宽度 ! b3 \( S) B# E1 S' L' R
JTable组件有几个控制表格特性的类和接口。TableColumn会不断追踪列的宽度,并负责列大小的调整,包括最大和最小宽度。 5 W- L) |+ N0 T# V- ?
TableColumnModel管理着TableColumns的集合以及列的选择。要设置某个列的宽度,就要为表格列的模型设置一个参照。然后,取得想要的TableColumn并调用其setPreferredWidth()方法
3 U _# n) b, T* e# v3 [; H TableColumncolumn = table.getColumnModel().getColumn(0); ) n. `: `1 N- f9 v
column.setPreferredWidth(100);
5 z" ^5 |1 H! }7 P& p 当用户拖放列的时候,列的索引并不会发生改变。getColumn(0)方法会一直返回正确的列,无论它出现在屏幕的哪个地方。 2 B& g2 q3 r& {
标题
$ z3 L4 R. k4 Y" ?7 z JtableHeader会处理JTable标题的显示。你可以细分JtableHeader以获得自定义的布局。例如,如果你的应用程序需要一个跨越多个列的标题,那么只用简单地细分JtableHeader并将它集成到你的JTable里就行了。
5 n# X% @6 X7 Q 你可以通过为当前JTable的JtableHeader设置一个参照或者调用其setReorderingAllowed()方法,来指定标题的重新排序是否被允许
3 O* |; e6 ?5 W) |' S! E7 w: o table.getTableHeader().setReorderingAllowed(false);
0 ?1 R* m; T# b% R; n 类似地,你可以确信列不会因为在列标题之间拖动而改变大小。要达到这个目的,你就要使用setResizingAllowed()方法
* Y5 u7 i1 t- k' d$ v e9 p table.getTableHeader().setResizingAllowed(false); 8 M2 |9 e2 M6 w; `
选择模式 - z0 P3 P D( U5 J; @( `2 F' W! e
在缺省状况下,当用户在JTable里选择一个单元格的时候,整个行都被选中了。有多种方法能够让用户自定义选择的方式。利用ListSelectionModel接口,你可以允许用户选择单个或者多个行
x. C8 `/ ^, Z( u table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+ U3 }9 y* c, n. E( i* b, T: S ListSelectionModel有下面这些字段
1 f+ W9 y; f# H8 g) u SINGLE_SELECTION允许一次选择一行。 & l" }1 p7 D x8 E9 t+ B; o
SINGLE_INTERVAL_SELECTION允许选择相邻的一系列行。
6 S' g I6 c0 ?# e* S5 [ MULTIPLE_INTERVAL_SELECTION也允许选择相邻的列,但是带有扩展功能。它允许用户使用[Ctrl]键进行多个互不相邻的选择(即选择不相邻的行)。
! q- M6 k8 P& J$ ~1 I; ] setCellSelectionEnabled()方法让用户能够同时选择单个单元格或者整个行 9 L1 m+ ^$ w3 C& y i8 l. f
table.setCellSelectionEnabled(true); / ^6 ?" o; {/ K( T r
如果被设置为是,setCellSelectionEnabled()方法还会允许在选择行和单个单元格的同时选择列,如果图B所示。
, a7 g. A2 p3 `/ ^: Q4 w 编辑单元格 & J R/ @: J- |
我们这个简单的表格允许用户编辑表格里的任何单元格。Listing B列出了一个表格,它允许由程序员来决定哪些单元格能够被编辑。第一步是创建一个自定义的TableModel
9 u5 @9 ~7 m! {9 l; | class SimpleTableModel extends AbstractTableModel {}
; B% Z R5 O. ?( R5 a 数据被封装在TableModel里,当JTable初始化的时候,自定义的TableModel就被作为一个参数传递给JTable的构造函数而不是那个二维的对象数组
d/ D0 {7 u1 s, i" ^ SimpleTableModelmyModel = new SimpleTableModel();
" v0 U" J, p0 ]' ]: x JTable table = new JTable(myModel); $ p& `2 w$ g" c/ _! k; \; ?1 u, t
如果想让第二列和第三列也变得可以编辑,并把第一列变成恒定的,那么你就要强制替代TableModel的isCellEditable()方法 9 a# x" W. @% j1 a/ Q5 v0 u
public booleanisCellEditable(int row, intcol){ 9 w5 T6 z0 H& \& y7 P) \' M
if (col == 0) {return false;} 3 ], z3 Z" H( C' U z B
else {return true; }
; j$ k6 V: R0 S0 R3 U4 ~ } 6 e; h' {* w6 @% H% m
简单的表格验证
3 h% B* ^* K) f& w8 y$ d. F- c" v- p 你需要确保用户只输入整数值,假如说,向第二列(“盒子的数量”这一列)输入值来强制替代setValueAt()方法,并将验证逻辑包括进这个新方法里。首先,你要检查列是否是整数,以及这个列是否只应该包含整数值
+ X' H( ~0 ?1 g0 s7 K; U+ x if (data[0][col] instanceof Integer && !(value instanceof Integer)) : g6 o4 N' g/ l/ @ U
{… } else { data[row][col] = value;}
( ^# y/ d% G. n9 J- F- s 然后,检查被插入的值是否是个整数。如果它不是的,那么这个字段就不应该被更新,而且应该要显示一条错误信息
+ w, e7 B! {4 J try { 2 G! D4 o" C6 K+ @' \+ l
data[row][col] = new Integer(value.toString());
* i- z& [0 C' Q. T! X, L } catch (NumberFormatException e) { * W* z% {/ `! J0 z
JOptionPane.showMessageDialog(SimpleTable.this, , X' E: B" K- g! S# R
"Please enter only integer values."); }
7 V5 H: C) Y9 g0 T背景颜色 1 F6 T0 Q, s# V
Listing C包含了用于ColorTable.java的代码,它说明了如何向JTable加入颜色。你可以通过强制替代其prepareRenderer()方法来向JTable加入背景颜色
1 m) @! Q+ R. L1 h JTable table = new JTable(data, columnNames){ ' s: I( g1 z. R& m) |% t
public Component prepareRenderer(TableCellRenderer r, int row, intcol){} 0 D" }4 w$ o! J
};
% ]: y6 a) ?5 O3 k5 ` 然后,插入决定哪些列应该有颜色以及应该是什么颜色的逻辑 9 H2 s8 g. | x6 q! x/ h
if (col == 2 && !isCellSelected(row, col)){ % e: t7 _+ [+ |; `
Color bg = new Color(200, 100, 30); & z# x! f0 m+ a3 t! c
c.setBackground(bg);
6 x: H4 |7 N m" e/ k c.setForeground(Color.white); ( l9 ~8 t2 K: [& y( f g
}要注意,当你更改单元格背景颜色的时候,你还应该更该单元格里所显示的文本的颜色,让其变得更加易读。图C显示了一个第一列和第二列加上了颜色的JTable。 ( [9 G' v7 U2 i0 N4 a1 u
一切皆在掌握中
& H# ~& C% L5 \, `$ Y9 N. c 我们的例子只是JTable其他部分的基础。通过使用这些工具,你能够快速和轻易地掌控对Java应用程序所生成的表格的格式化,这样就能够让你的用户在进行正常使用的时候不碰到障碍。
: e% u& P5 B. X0 s7 b, ~( |0 d ------------------------------------------------------------------- --------------------------------------------------------------- 9 O0 z- }- n6 x9 `" s/ m! }* {6 S
import java.awt.Dimension;
# H' G7 A5 [4 m0 k! T8 J7 V! s7 q7 O, ^' z import javax.swing.JFrame;
8 g! j* B& X3 J" _% ~' y import javax.swing.JScrollPane;
( g% W5 |# c- r! }( q s. w, Y% H import javax.swing.JPanel;
7 g$ }3 v- u5 ?" |* {, h5 ? import javax.swing.JTable; : ~& j3 ~; D9 p6 q; m, R! E
import java.awt.Color;
* f- |0 \2 L8 v import java.awt.GridLayout;
0 k4 `7 G% ]; U4 H7 J7 p import javax.swing.table.TableColumn;
$ [( i; h* Q3 V) ~: ? public class JTableDemo . O2 O0 @' I2 ^# k6 c1 X
{ ) O# x" n. ?; N& I: g
public static void main (String[] args)
3 S- T/ E& p- Y: U; O' Y { & @* x* j# Y9 a) n5 I
/*
; K$ T' b' D$ h! `2 C 构造函数有很多下面先介绍几个:
# c. n4 K! q! u u JTable()
7 r' n3 G* K* U5 }3 c2 d0 R JTable(int numRows, int numColumns)
. x7 G: H$ F; e. c8 x0 F JTable(Object[][] rowData, Object[] columnNames)
1 e+ Z' _6 k# E& h! M1 O. k; _- |! ~ */ 6 o4 Z# r6 Q7 F# R, k+ N
JTable example1 = new JTable ();//看不到但存在 * r: J6 [' H8 {9 r. I5 I2 L
JTable example2 = new JTable (8, 6); 0 M3 U" r5 C+ b" E2 f. a
final Object[] columnNames = {"姓名", "性别", "家庭地址",//列名最好用final修饰 / Y: s+ F4 Q" d0 n
"电话号码", "生日", "工作", "收入", "婚姻状况","恋爱状况"};
# u/ Y2 I# u6 o Object[][] rowData = { , i4 M! ]5 @, }& D3 p, s7 ^
{"ddd", "男", "江苏南京", "1378313210", "03/24/1985", "学生", "寄生中", "未婚", "没"}, ) J5 H# `6 q2 O+ p. z
{"eee", "女", "江苏南京", "13645181705", "xx/xx/1985", "家教", "未知", "未婚", "好象没"},
6 i. r0 p) [# H {"fff", "男", "江苏南京", "13585331486", "12/08/1985", "汽车推销员", "不确定", "未婚", "有"},
& K0 ?6 G) K9 j4 t4 m- F3 B {"ggg", "女", "江苏南京", "81513779", "xx/xx/1986", "宾馆服务员", "确定但未知", "未婚", "有"}, ; P% m% @& M' _
{"hhh", "男", "江苏南京", "13651545936", "xx/xx/1985", "学生", "流放中", "未婚", "无数次分手后没有"} 0 A4 S) t5 Q( q9 o& l2 N
}; 4 {. V, T3 t! a
JTable friends = new JTable (rowData, columnNames); & i2 z. y5 O' ]. M& x
friends.setPreferredScrollableViewportSize(new Dimension(600, 100));//设置表格的大小 6 @8 q) b; a' N5 v( j p. I
friends.setRowHeight (30);//设置每行的高度为20 ! q* q- `4 x* I1 H* s7 x0 w
friends.setRowHeight (0, 20);//设置第1行的高度为15 0 r# C) j* l9 t5 ~; h: A/ F! q
friends.setRowMargin (5);//设置相邻两行单元格的距离 6 q6 V0 M# s4 v8 z* \0 _
friends.setRowSelectionAllowed (true);//设置可否被选择.默认为false
: _% d4 R% @. C# q' F friends.setSelectionBackground (Color.white);//设置所选择行的背景色
. E" y% P* ?( F% g: J2 n friends.setSelectionForeground (Color.red);//设置所选择行的前景色
5 L& i0 u2 F: Z% J friends.setGridColor (Color.black);//设置网格线的颜色
9 j" @ e% a+ M F friends.selectAll ();//选择所有行
" ^; m) p# X$ O! ] friends.setRowSelectionInterval (0,2);//设置初始的选择行,这里是1到3行都处于选择状态
6 V( t& T B" _& z friends.clearSelection ();//取消选择
7 H# t: i( I" l: J! f0 H% E9 q friends.setDragEnabled (false);//不懂这个 ; {7 ?# a: X5 ~
friends.setShowGrid (false);//是否显示网格线 7 R* W( x" X& y- D0 y
friends.setShowHorizontalLines (false);//是否显示水平的网格线 ! d1 r' u; n5 u
friends.setShowVerticalLines (true);//是否显示垂直的网格线
9 j+ c$ C$ k& J; M; Q; T% s friends.setValueAt ("tt", 0, 0);//设置某个单元格的值,这个值是一个对象 ; f' q, a. s$ v2 z g0 V
friends.doLayout (); ; t A: F$ T6 S* S6 v. g
friends.setBackground (Color.lightGray); 7 r) \; L7 k/ y5 \; V' M, q8 Y. p
JScrollPane pane1 = new JScrollPane (example1);//JTable最好加在JScrollPane上
3 l8 ^( j x. d) e JScrollPane pane2 = new JScrollPane (example2);
* F! P8 Q" g) l& ] JScrollPane pane3 = new JScrollPane (friends); ! |9 g$ g6 L) n3 M" l
JPanel panel = new JPanel (new GridLayout (0, 1));
; k2 d+ |8 r/ }) J0 K panel.setPreferredSize (new Dimension (600,400));
/ l, L6 R' g( ^ panel.setBackground (Color.black);
/ b" b$ \; k5 i7 T" [ panel.add (pane1); 2 d: j& b/ D5 G2 F5 i8 l
panel.add (pane2);
" n* l* I" \( I3 d panel.add (pane3);
# b5 [6 w) F# v% f4 y) b9 S JFrame frame = new JFrame ("JTableDemo"); ! ?& k ~$ r* ^& z
frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
- v$ I: o' }% o% {% k- ~- q frame.setContentPane (panel);
1 Q* ]. |3 _: F* R8 M6 F$ } frame.pack(); ) I$ w+ r6 K ^( l# e$ e" E
frame.show(); }; |