具体思路:
1.
我们可以考虑使用两个
JTable
(
fixTable
,
mainTable
)
2.
定义一个
JScrollPane,
把
mainTable
放在他的
viewPort
中,
3.
在新
new
一个
JViewport
,把
fixTable
放在他的上面
4.
利用
JScrollPane
的
setRowHeaderView
()方法,把这个
JViewport
作为他的
RowHeader
5.
最后把
fixTable
的
tableHeader
放在
JScrollPane
的左上方(利用
setCorner
方法
)
6.
实现选中的同步,因为是
2
个
table,
所以我们要人工实现他的同步,使用户开着好象一个
table.
7.
有的时候我们可能还要在表格上监听鼠标事件,那么这个我们如何同步呢,我的想法是我们增加鼠标事件时只给
mainTable
添加,而
fixTable
的鼠标事件默认调用
mainTable
的处理方法,从而实现事件的传递。
好了
下面我们来看一下代码:
首先是我封装好的
FixTable
类
(1)
import
java.awt.event.MouseAdapter;
(2)
import
java.awt.event.MouseEvent;
(3)
import
java.awt.event.MouseListener;
(4)
(5)
import
javax.swing.JScrollPane;
(6)
import
javax.swing.JTable;
(7)
import
javax.swing.JViewport;
(8)
import
javax.swing.ListSelectionModel;
(9)
import
javax.swing.event.ListSelectionEvent;
(10)
import
javax.swing.event.ListSelectionListener;
(11)
import
javax.swing.table.AbstractTableModel;
(12)
(13)
public
class
FixTable {
(14)
private
JTable
mainTable
;
(15)
private
JTable
fixTable
;
(16)
private
FixTableModel
fixModel
;
(17)
private
MainTableModel
mainModel
;
(18)
private
int
fixColumnCount
;
//
冻结的列数
(19)
private
String[]
columnHeader
;
//
表头
(20)
private
JScrollPane
mainScroll
;
//
装载在父
Container
的组件
(21)
(22)
// private Vector tableData = new Vector(); //
表格中数据
(23)
private
Object[][]
tableData
;
(24)
(25)
public
FixTable(
int
fixColumnCount, String[] columnHeader,
(26)
Object[][] tableData) {
(27)
this
.
fixColumnCount
= fixColumnCount;
(28)
this
.
columnHeader
= columnHeader;
(29)
this
.
tableData
= tableData;
//
(30)
this
.initComponents();
(31)
}
(32)
(33)
/**
(34)
*
初始化界面
(35)
*/
(36)
private
void
initComponents() {
(37)
mainTable
=
new
JTable();
(38)
fixTable
=
new
JTable();
(39)
mainModel
=
new
MainTableModel();
(40)
fixModel
=
new
FixTableModel();
(41)
mainTable
.setModel(
mainModel
);
(42)
mainTable
.setAutoResizeMode(JTable.
AUTO_RESIZE_OFF
);
(43)
mainTable
.setSelectionMode(ListSelectionModel.
SINGLE_SELECTION
);
(44)
fixTable
.setModel(
fixModel
);
(45)
fixTable
.setAutoResizeMode(JTable.
AUTO_RESIZE_OFF
);
(46)
fixTable
.setSelectionMode(ListSelectionModel.
SINGLE_SELECTION
);
(47)
(48)
mainTable
.getSelectionModel().addListSelectionListener(
(49)
new
ListSelectionListener() {
(50)
(51)
@Override
(52)
public
void
valueChanged(ListSelectionEvent e) {
(53)
//
TODO
Auto-generated method stub
(54)
checkSelection(
false
);
(55)
}
(56)
(57)
});
(58)
fixTable
.getSelectionModel().addListSelectionListener(
(59)
new
ListSelectionListener() {
(60)
@Override
(61)
public
void
valueChanged(ListSelectionEvent e) {
(62)
//
TODO
Auto-generated method stub
(63)
checkSelection(
true
);
(64)
}
(65)
});
(66)
(67)
//
添加鼠标事件同步两个表的鼠标双击事件
(68)
mainTable
.addMouseListener(
new
MouseAdapter() {
(69)
public
void
mouseClicked(MouseEvent e) {
(70)
if
(e.getClickCount() > 1) {
(71)
if
(e.getSource().equals(
mainTable
)) {
(72)
MouseListener[] mls = (MouseListener[])
fixTable
(73)
.getListeners(MouseListener.
class
);
(74)
for
(
int
i = 0; i < mls.
length
; i++)
(75)
mls[i].mouseClicked(e);
(76)
}
(77)
(78)
}
(79)
}
(80)
});
(81)
(82)
fixTable
.addMouseListener(
new
MouseAdapter() {
(83)
public
void
mouseClicked(MouseEvent e) {
(84)
if
(e.getClickCount() > 1) {
(85)
if
(e.getSource().equals(
fixTable
)) {
(86)
System.
out
.println(
"
首先点击了冻结列
"
);
(87)
}
else
{
(88)
System.
out
.println(
"
首先点击了内容列
"
);
(89)
}
(90)
// if (e.getSource().equals(fixTable)) {
(91)
// MouseListener[] mls = (MouseListener[]) mainTable
(92)
// .getListeners(MouseListener.class);
(93)
// for (int i = 0; i < mls.length; i++)
(94)
// mls[i].mouseClicked(e);
(95)
// }
(96)
}
(97)
}
(98)
});
(99)
(100)
mainScroll
=
new
JScrollPane();
(101)
mainScroll
.getViewport().add(
mainTable
);
(102)
(103)
JViewport fixPort =
new
JViewport();
(104)
fixPort.setPreferredSize(
fixTable
.getPreferredSize());
(105)
fixPort.add(
fixTable
);
(106)
mainScroll
.setRowHeaderView(fixPort);
(107)
mainScroll
.setCorner(JScrollPane.
UPPER_LEFT_CORNER
,
fixTable
(108)
.getTableHeader());
(109)
}
(110)
(111)
/**
(112)
*
在表格中放入数据
(113)
*
(114)
*
@param
tableData
(115)
*/
(116)
public
void
setData(Object[][] tableData) {
(117)
this
.
tableData
= tableData;
(118)
}
(119)
(120)
/**
(121)
*
返回冻结表格的内容面板
使用
panel.add(table.getTableContentPane());
才能使表格加到容器中
(122)
*
(123)
*
@return
(124)
*/
(125)
public
JScrollPane getTableContentPane() {
(126)
return
mainScroll
;
(127)
}
(128)
(129)
/**
(130)
*
使两个
table
同时响应选中事件
(131)
*
(132)
*
@param
isFixedTable
(133)
*/
(134)
private
void
checkSelection(
boolean
isFixedTable) {
(135)
int
fixedSelectedIndex =
fixTable
.getSelectedRow();
(136)
int
selectedIndex =
mainTable
.getSelectedRow();
(137)
if
(fixedSelectedIndex != selectedIndex) {
(138)
if
(isFixedTable) {
(139)
mainTable
.setRowSelectionInterval(fixedSelectedIndex,
(140)
fixedSelectedIndex);
(141)
}
else
{
(142)
fixTable
.setRowSelectionInterval(selectedIndex, selectedIndex);
(143)
}
(144)
}
(145)
(146)
}
(147)
(148)
/**
(149)
*
冻结的列表模型
(150)
*
(151)
*
@author
benson
(152)
*
(153)
*/
(154)
private
class
FixTableModel
extends
AbstractTableModel {
(155)
(156)
@Override
(157)
public
int
getColumnCount() {
(158)
//
TODO
Auto-generated method stub
(159)
return
fixColumnCount
;
(160)
}
(161)
(162)
@Override
(163)
public
int
getRowCount() {
(164)
//
TODO
Auto-generated method stub
(165)
return
tableData
.
length
;
(166)
}
(167)
(168)
@Override
(169)
public
Object getValueAt(
int
rowIndex,
int
columnIndex) {
(170)
//
TODO
Auto-generated method stub
(171)
if
(
tableData
[rowIndex][columnIndex] !=
null
)
(172)
return
tableData
[rowIndex][columnIndex];
(173)
return
""
;
(174)
}
(175)
(176)
public
String getColumnName(
int
column) {
(177)
return
columnHeader
[column];
(178)
}
(179)
}
(180)
(181)
/**
(182)
*
数据列表模型
(183)
*
(184)
*
@author
benson
(185)
*
(186)
*/
(187)
private
class
MainTableModel
extends
AbstractTableModel {
(188)
(189)
@Override
(190)
public
int
getColumnCount() {
(191)
//
TODO
Auto-generated method stub
(192)
return
columnHeader
.
length
-
fixColumnCount
;
(193)
}
(194)
(195)
@Override
(196)
public
int
getRowCount() {
(197)
//
TODO
Auto-generated method stub
(198)
return
tableData
.
length
;
(199)
}
(200)
(201)
@Override
(202)
public
Object getValueAt(
int
rowIndex,
int
columnIndex) {
(203)
//
TODO
Auto-generated method stub
(204)
if
(
tableData
[rowIndex][columnIndex +
fixColumnCount
] !=
null
)
(205)
return
tableData
[rowIndex][columnIndex +
fixColumnCount
];
(206)
return
""
;
(207)
}
(208)
(209)
public
String getColumnName(
int
column) {
(210)
return
columnHeader
[column +
fixColumnCount
];
(211)
}
(212)
(213)
}
(214)
}
测试主函数
import
java.awt.BorderLayout;
import
java.awt.Dimension;
import
javax.swing.JFrame;
import
javax.swing.JPanel;
public
class
FixTableFrame
extends
JFrame {
private
FixTable
table
;
/**
*
Launch
the
application
*
*
@param
args
*/
public
static
void
main(String args[]) {
try
{
FixTableFrame frame =
new
FixTableFrame();
frame.setVisible(
true
);
frame.pack();
}
catch
(Exception e) {
e.printStackTrace();
}
}
/**
*
Create
the
frame
*/
public
FixTableFrame() {
super
(
"
冻结表头
"
);
this
.setPreferredSize(
new
Dimension(300, 200));
setDefaultCloseOperation(JFrame.
EXIT_ON_CLOSE
);
final
JPanel panel =
new
JPanel();
panel.setLayout(
new
BorderLayout());
getContentPane().add(panel, BorderLayout.
CENTER
);
String[] columns =
new
String[] {
"
姓名
"
,
"
学号
"
,
"
英语
"
,
"
语文
"
,
"
数学
"
,
"
综合
"
};
Object[][] data =
new
Object[][] {
{
"Benson"
,
"1"
,
"84"
,
"74"
,
"65"
,
"76"
},
{
"Jim"
,
"2"
,
"63"
,
"77"
,
"88"
,
"99"
},
{
"King"
,
"3"
,
"78"
,
"76"
,
"56"
,
"98"
},
{
"Laura"
,
"4"
,
"98"
,
"76"
,
"87"
,
"66"
},
{
"Fisher"
,
"5"
,
"76"
,
"46"
,
"86"
,
"45"
},
{
"Mike"
,
"6"
,
"54"
,
"78"
,
"67"
,
"44"
} };
table
=
new
FixTable(1, columns, data);
// table.setData(data);
//
此方法一定调用
//
不能用
panel.add(table);
因为
table
已经不是一个
Component
而是一个合成组件
panel.add(
table
.getTableContentPane());
}
}
结束语:当然这个表格功能还不完善,还需要添加刷新,增加,删除等功能,实现起来并不复杂,那就大家自己来实现吧。
效果图: