表头合并单元格. 照例不多说了, 看代码吧.
首先需要定义一个接口, 看看表头是怎么合并的
/** */
/**
* 列头组
*
* @author Brad.Wu
* @version 1.0
*/

public
interface
Group
...
{

/** *//**
* 获取所在行
*
* @return
*/
public int getRow();


/** *//**
* 获取所在列
*
* @return
*/
public int getColumn();


/** *//**
* 获取占列个数
*
* @return
*/
public int getColumnSpan();


/** *//**
* 获取占行个数
*
* @return
*/
public int getRowSpan();


/** *//**
* 获取文字
*
* @return
*/
public Object getHeaderValue();
}
这个和HTML的写法其实一样的. 主要就是每个Cell所在的位置, 占的行列数以及文字.
接下来是一个默认的实现. 其实不写接口也可以, 因为通常不会对表头做动作的.
/** */
/**
* 默认Group实现
*
* @author Brad.Wu
* @version 1.0
*/

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;


/**//*
* (非 Javadoc)
*
* @see com.eplat.realty.view.component.table.Group#getRow()
*/

public int getRow() ...{
return this.row;
}


/** *//**
* @param row 要设置的 row。
*/

public void setRow(int row) ...{
this.row = row;
}


/**//*
* (非 Javadoc)
*
* @see com.eplat.realty.view.component.table.Group#getColumn()
*/

public int getColumn() ...{
return this.column;
}


/** *//**
* @param column 要设置的 column。
*/

public void setColumn(int column) ...{
this.column = column;
}


/**//*
* (非 Javadoc)
*
* @see com.eplat.realty.view.component.table.Group#getColumnSpan()
*/

public int getColumnSpan() ...{
return this.columnSpan;
}


/** *//**
* @param columnSpan 要设置的 columnSpan。
*/

public void setColumnSpan(int columnSpan) ...{
this.columnSpan = columnSpan;
}


/**//*
* (非 Javadoc)
*
* @see com.eplat.realty.view.component.table.Group#getRowSpan()
*/

public int getRowSpan() ...{
return this.rowSpan;
}


/** *//**
* @param rowSpan 要设置的 rowSpan。
*/

public void setRowSpan(int rowSpan) ...{
this.rowSpan = rowSpan;
}


/**//*
* (非 Javadoc)
*
* @see com.eplat.realty.view.component.table.Group#getHeaderValue()
*/

public Object getHeaderValue() ...{
return this.headerValue;
}


/** *//**
* @param headerValue 要设置的 headerValue。
*/

public void setHeaderValue(Object headerValue) ...{
this.headerValue = headerValue;
}
}
重写一个表头组件
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;


/** */
/**
* 可以合并的列头
*
* @author Brad.Wu
* @version 1.0
*/
@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);
}


/**//*
* (非 Javadoc)
*
* @see javax.swing.table.JTableHeader#updateUI()
*/
@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 (colu