转载: 表头合并单元格. JTable Groupable TableHeader
http://blog.csdn.net/bradwoo8621/article/details/1541835
表头合并单元格. 照例不多说了, 看代码吧.
首先需要定义一个接口, 看看表头是怎么合并的
package jtble;
public interface Group {
public int getRow();
public int getColumn();
public int getColumnSpan();
public int getRowSpan();
public Object getHeaderValue();
}
这个和HTML的写法其实一样的. 主要就是每个Cell所在的位置, 占的行列数以及
文字.
接下来是一个默认的实现. 其实不写接口也可以, 因为通常不会对表头做动作的.
package jtble;
public class DefaultGroup implements Group {
private int row = 0;
private int column = 0;
private int rowSpan = 1;
private int columnSpan = 1;
private Object headerValue = null;
public int getRow() {
return this.row;
}
public void setRow(int row) {
this.row = row;
}
public int getColumn() {
return this.column;
}
public void setColumn(int column) {
this.column = column;
}
public int getColumnSpan() {
return this.columnSpan;
}
public void setColumnSpan(int columnSpan) {
this.columnSpan = columnSpan;
}
public int getRowSpan() {
return this.rowSpan;
}
public void setRowSpan(int rowSpan) {
this.rowSpan = rowSpan;
}
public Object getHeaderValue() {
return this.headerValue;
}
public void setHeaderValue(Object headerValue) {
this.headerValue = headerValue;
}
}
重写一个表头组件
package jtble;
import java.awt.Component;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JTable;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumnModel;
@SuppressWarnings("serial")
public class GroupableTableHeader extends JTableHeader {
private int rowCount = 0;
private int columnCount = 0;
private List<Group> groups = new ArrayList<Group>();
public GroupableTableHeader() {
// 这个是必须的, 因为如果可以拖动列的位置, 那么一切都完
蛋了.
// 如果你想实现这个功能, 那么只能你自己去做了, 我可不想
做这个, 看上去超烦的
this.setReorderingAllowed(false);
}
@Override
public void updateUI() {
setUI(new GroupableTableHeaderUI());
}
public Rectangle getHeaderRect(int row, int column) {
Rectangle r = new Rectangle();
TableColumnModel cm = getColumnModel();
Group group = this.getGroup(row, column);
r.height = getHeight();
if (column < 0) {
// x = width = 0;
if (!getComponentOrientation().isLeftToRight()) {
r.x = getWidthInRightToLeft();
}
} else if (column >= cm.getColumnCount()) {
if (getComponentOrientation().isLeftToRight()) {
r.x = getWidth();
}
} else {
for (int i = 0; i < group.getColumn(); i++) {
r.x += cm.getColumn(i).getWidth();
}
for (int i = group.getColumn(), j =
group.getColumn() +
group.getColumnSpan() - 1; i < j; i++) {
r.width += cm.getColumn(i).getWidth();
}
if (!getComponentOrientation().isLeftToRight()) {
r.x = getWidthInRightToLeft() - r.x -
r.width;
}
// r.width = cm.getColumn(column).getWidth();
}
return r;
}
public int getYOfGroup(Group group) {
int row = group.getRow();
TableCellRenderer renderer = this.getDefaultRenderer();
Component comp =
renderer.getTableCellRendererComponent(getTable
(), group.getHeaderValue(), false, false, group.getRow(),
group
.getColumn());
return row * comp.getPreferredSize().height;
}
public int getHeightOfGroup(Group group) {
int rowSpan = group.getRowSpan();
TableCellRenderer renderer = this.getDefaultRenderer();
Component comp =
renderer.getTableCellRendererComponent(getTable
(), group.getHeaderValue(), false, false, group.getRow(),
group
.getColumn());
return rowSpan * comp.getPreferredSize().height;
}
private int getWidthInRightToLeft() {
if ((table != null) && (table.getAutoResizeMode() !=
JTable.AUTO_RESIZE_OFF)) {
return table.getWidth();
}
return super.getWidth();
}
public void addGroup(Group group) {
groups.add(group);
int row = group.getRow();
int rowSpan = group.getRowSpan();
rowCount = Math.max(rowCount, row + rowSpan);
int column = group.getColumn();
int columnSpan = group.getColumnSpan();
columnCount = Math.max(columnCount, column +
columnSpan);
}
public void removeAllGroups() {
groups.clear();
}
public List<Group> getGroups() {
List<Group> list = new ArrayList<Group>();
list.addAll(groups);
return list;
}
public List<Group> getGroupsAtColumn(int columnIndex) {
List<Group> list = new ArrayList<Group>();
for (Group group : groups) {
int minColumnIndex = group.getColumn();
int maxColumnIndex = minColumnIndex +
group.getColumnSpan() -
1;
if (minColumnIndex <= columnIndex &&
maxColumnIndex >=
columnIndex) {
list.add(group);
}
}
return list;
}
public List<Group> getGroupsAtRow(int rowIndex) {
List<Group> list = new ArrayList<Group>();
for (Group group : groups) {
int minRowIndex = group.getRow();
int maxRowIndex = minRowIndex +
group.getRowSpan() - 1;
if (minRowIndex <= rowIndex && maxRowIndex
>= rowIndex) {
list.add(group);
}
}
return list;
}
public int getRowCount() {
return this.rowCount;
}
public int getColumnCount() {
return this.columnCount;
}
@Override
public void setTable(JTable table) {
super.setColumnModel(table.getColumnModel());
super.setTable(table);
}
public Group getGroup(int row, int column) {
for (Group group : groups) {
int rowIndex = group.getRow();
int columnIndex = group.getColumn();
int rowSpan = group.getRowSpan();
int columnSpan = group.getColumnSpan();
if (rowIndex <= row && rowIndex + rowSpan >
row &&
columnIndex <= column && columnIndex +
columnSpan > column)
return group;
}
return null;
}
@Override
protected TableCellRenderer createDefaultRenderer() {
return new TableHeaderRenderer();
}
}
常量类:
package jtble;
public class Constants {
static int TABLE_ROW_HEIGHT = 20;
}
里面用到的TableHeaderRenderer, 没什么花头的, 贴出来看看
package jtble;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.io.Serializable;
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellRenderer;
@SuppressWarnings("serial")
public class TableHeaderRenderer extends JLabel implements
TableCellRenderer,
Serializable {
public TableHeaderRenderer() {
setOpaque(true);
setHorizontalAlignment(JLabel.CENTER);
}
// implements javax.swing.table.TableCellRenderer
public Component getTableCellRendererComponent(JTable table,
Object value,
boolean isSelected, boolean hasFocus, int row,
int column) {
if (table != null) {
JTableHeader header = table.getTableHeader();
if (header != null) {
setForeground(header.getForeground
());
setBackground(header.getBackground
());
setFont(header.getFont());
}
}
setBorder(UIManager.getBorder
("TableHeader.cellBorder"));
setValue(value);
Dimension dim = getPreferredSize();
if (dim.height < Constants.TABLE_ROW_HEIGHT)
setPreferredSize(new Dimension
(getPreferredSize().width,
Constants.TABLE_ROW_HEIGHT));
return this;
}
public boolean isOpaque() {
Color back = getBackground();
Component p = getParent();
if (p != null) {
p = p.getParent();
}
// p should now be the JTable.
boolean colorMatch = (back != null) && (p != null)
&& back.equals(p.getBackground()) &&
p.isOpaque();
return !colorMatch && super.isOpaque();
}
public void invalidate() {
}
public void validate() {
}
public void revalidate() {
}
public void repaint(long tm, int x, int y, int width, int height) {
}
public void repaint(Rectangle r) {
}
public void repaint() {
}
protected void firePropertyChange(String propertyName, Object
oldValue,
Object newValue) {
// Strings get interned
if (propertyName == "text") {
super.firePropertyChange(propertyName,
oldValue, newValue);
}
}
public void firePropertyChange(String propertyName, boolean
oldValue,
boolean newValue) {
}
protected void setValue(Object value) {
setText((value == null) ? "" : value.toString());
}
public static class UIResource extends DefaultTableCellRenderer
implements
javax.swing.plaf.UIResource {
}
}
最重要的UI登场, 哈哈
package jtble;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.Enumeration;
import java.util.List;
import javax.swing.JComponent;
import javax.swing.plaf.basic.BasicTableHeaderUI;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
public class GroupableTableHeaderUI extends BasicTableHeaderUI {
@Override
public void paint(Graphics g, JComponent c) {
if (header.getColumnModel().getColumnCount() <= 0) {
return;
}
boolean ltr = header.getComponentOrientation
().isLeftToRight();
Rectangle clip = g.getClipBounds();
Point left = clip.getLocation();
Point right = new Point(clip.x + clip.width - 1, clip.y);
TableColumnModel cm = header.getColumnModel();
int cMin = header.columnAtPoint(ltr ? left : right);
int cMax = header.columnAtPoint(ltr ? right : left);
// This should never happen.
if (cMin == -1) {
cMin = 0;
}
// If the table does not have enough columns to fill the
view we'll get
// -1.
// Replace this with the index of the last column.
if (cMax == -1) {
cMax = cm.getColumnCount() - 1;
}
// TableColumn draggedColumn =
header.getDraggedColumn();
int columnWidth;
// Rectangle cellRect = header.getHeaderRect(ltr ? cMin :
cMax);
TableColumn aColumn;
// if (ltr) {
// for (int column = cMin; column <= cMax; column++) {
// aColumn = cm.getColumn(column);
// columnWidth = aColumn.getWidth();
// cellRect.width = columnWidth;
// // if (aColumn != draggedColumn) {
// paintCell(g, cellRect, column);
// // }
// cellRect.x += columnWidth;
// }
// } else {
// for (int column = cMax; column >= cMin; column--) {
// aColumn = cm.getColumn(column);
// columnWidth = aColumn.getWidth();
// cellRect.width = columnWidth;
// // if (aColumn != draggedColumn) {
// paintCell(g, cellRect, column);
// // }
// cellRect.x += columnWidth;
// }
// }
GroupableTableHeader gHeader =
(GroupableTableHeader) header;
for (int row = 0, rowCount = gHeader.getRowCount(); row
< rowCount; row++) {
Rectangle cellRect = gHeader.getHeaderRect
(row, ltr ? cMin : cMax);
if (ltr) {
for (int column = cMin; column <=
cMax; column++) {
Group group =
gHeader.getGroup(row, column);
cellRect.width = 0;
for (int from =
group.getColumn(), to = from
+
group.getColumnSpan() - 1; from <= to; from++) {
aColumn =
cm.getColumn(from);
columnWidth =
aColumn.getWidth();
cellRect.width +=
columnWidth;
}
cellRect.y =
gHeader.getYOfGroup(group);
cellRect.height =
gHeader.getHeightOfGroup(group);
paintCell(g, cellRect, row,
column);
cellRect.x += cellRect.width;
column +=
group.getColumnSpan() - 1;
}
} else {
for (int column = cMax; column >=
cMin; column--) {
Group group =
gHeader.getGroup(row, column);
cellRect.width = 0;
for (int from =
group.getColumn(), to = from
+
group.getColumnSpan() - 1; from <= to; from++) {
aColumn =
cm.getColumn(from);
columnWidth =
aColumn.getWidth();
cellRect.width +=
columnWidth;
}
paintCell(g, cellRect, row,
column);
cellRect.x += cellRect.width;
column -=
group.getColumnSpan() - 1;
}
}
}
// Remove all components in the rendererPane.
rendererPane.removeAll();
}
private void paintCell(Graphics g, Rectangle cellRect, int rowIndex,
int columnIndex) {
Component component = getHeaderRenderer(rowIndex,
columnIndex);
rendererPane.paintComponent(g, component, header,
cellRect.x,
cellRect.y, cellRect.width,
cellRect.height, true);
}
private Component getHeaderRenderer(int rowIndex, int
columnIndex) {
GroupableTableHeader gHeader =
(GroupableTableHeader) header;
Group group = gHeader.getGroup(rowIndex,
columnIndex);
TableCellRenderer renderer = header.getDefaultRenderer
();
return renderer.getTableCellRendererComponent
(header.getTable(), group
.getHeaderValue(), false, false, -1,
columnIndex);
}
private int getHeaderHeight() {
int height = 0;
int tempHeight = 0;
GroupableTableHeader gHeader =
(GroupableTableHeader) header;
TableColumnModel cm = header.getColumnModel();
for (int column = 0, columnCount = cm.getColumnCount();
column < columnCount; column++) {
tempHeight = 0;
List<Group> groups =
gHeader.getGroupsAtColumn(column);
for (Group group : groups) {
TableCellRenderer renderer =
gHeader.getDefaultRenderer();
Component comp =
renderer.getTableCellRendererComponent(header
.getTable(),
group.getHeaderValue(), false, false, -1,
column);
int rendererHeight =
comp.getPreferredSize().height;
tempHeight += rendererHeight;
}
height = Math.max(height, tempHeight);
}
return height;
}
private Dimension createHeaderSize(long width) {
// TableColumnModel columnModel =
header.getColumnModel();
// None of the callers include the intercell spacing, do it
here.
if (width > Integer.MAX_VALUE) {
width = Integer.MAX_VALUE;
}
return new Dimension((int) width, getHeaderHeight());
}
public Dimension getMinimumSize(JComponent c) {
long width = 0;
Enumeration enumeration = header.getColumnModel
().getColumns();
while (enumeration.hasMoreElements()) {
TableColumn aColumn = (TableColumn)
enumeration.nextElement();
width = width + aColumn.getMinWidth();
}
return createHeaderSize(width);
}
public Dimension getPreferredSize(JComponent c) {
long width = 0;
Enumeration enumeration = header.getColumnModel
().getColumns();
while (enumeration.hasMoreElements()) {
TableColumn aColumn = (TableColumn)
enumeration.nextElement();
width = width + aColumn.getPreferredWidth();
}
return createHeaderSize(width);
}
public Dimension getMaximumSize(JComponent c) {
long width = 0;
Enumeration enumeration = header.getColumnModel
().getColumns();
while (enumeration.hasMoreElements()) {
TableColumn aColumn = (TableColumn)
enumeration.nextElement();
width = width + aColumn.getMaxWidth();
}
return createHeaderSize(width);
}
}
最后顺便贴一个测试程序, 可以看看怎么用法. 文档我也没有写过
package jtble;
import java.awt.BorderLayout;
import java.awt.HeadlessException;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
@SuppressWarnings("serial")
public class Test extends JFrame {
public static void main(String[] args) {
Test test = new Test();
test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
test.setSize(800, 600);
test.setVisible(true);
}
private DefaultTableModel tableModel = new DefaultTableModel() {
@Override
public int getColumnCount() {
return 6;
}
@Override
public int getRowCount() {
return 2;
}
};
private JTable table = new JTable(tableModel);
private JScrollPane scroll = new JScrollPane(table);
public Test() throws HeadlessException {
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
GroupableTableHeader tableHeader = new
GroupableTableHeader();
table.setTableHeader(tableHeader);
DefaultGroup group = new DefaultGroup();
group.setRow(0);
group.setRowSpan(2);
group.setColumn(0);
group.setHeaderValue("楼层");
tableHeader.addGroup(group);
group = new DefaultGroup();
group.setRow(0);
group.setRowSpan(2);
group.setColumn(1);
group.setHeaderValue("水平/垂直系数");
tableHeader.addGroup(group);
group = new DefaultGroup();
group.setRow(0);
group.setColumn(2);
group.setColumnSpan(2);
group.setHeaderValue("A & B");
tableHeader.addGroup(group);
group = new DefaultGroup();
group.setRow(1);
group.setColumn(2);
group.setHeaderValue("Column A");
tableHeader.addGroup(group);
group = new DefaultGroup();
group.setRow(1);
group.setColumn(3);
group.setHeaderValue("Column B");
tableHeader.addGroup(group);
group = new DefaultGroup();
group.setRow(0);
group.setColumn(4);
group.setColumnSpan(2);
group.setHeaderValue("C & D");
tableHeader.addGroup(group);
group = new DefaultGroup();
group.setRow(1);
group.setColumn(4);
group.setHeaderValue("Column C");
tableHeader.addGroup(group);
group = new DefaultGroup();
group.setRow(1);
group.setColumn(5);
group.setHeaderValue("Column D");
tableHeader.addGroup(group);
getContentPane().add(scroll, BorderLayout.CENTER);
}
}