概述
表头合并单元格. 照例不多说了, 看代码吧.
首先需要定义一个接口, 看看表头是怎么合并的
/**
* 列头组
*
* @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();
}
* 列头组
*
* @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;
}
}
* 默认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 (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;
}
/**
* 获取Group的Y位置
*
* @param group
* @return
*/
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;
}
/**
* 获取Group的高度
*
* @param group
* @return
*/
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();
}
/**
* 增加Group
*
* @param group
*/
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);
}
/**
* 移除所有Group
*/
public void removeAllGroups() {
groups.clear();
}
/**
* 获取所有的Group
*
* @return
*/
public List<Group> getGroups() {
List<Group> list = new ArrayList<Group>();
list.addAll(groups);
return list;
}
/**
* 获取指定列上的Group
*
* @param columnIndex
* @return
*/
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;
}
/**
* 获取指定行上的所有Group
*
* @param rowIndex
* @return
*/
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;
}
/**
* 获取行数
*
* @return
*/
public int getRowCount() {
return this.rowCount;
}
/**
* @return Returns the columnCount.
*/
public int getColumnCount() {
return this.columnCount;
}
/*
* (非 Javadoc)
*
* @see javax.swing.table.JTableHeader#setTable(javax.swing.JTable)
*/
@Override
public void setTable(JTable table) {
super.setColumnModel(table.getColumnModel());
super.setTable(table);
}
/**
* 获取指定行列的Group
*
* @param row
* @param column
* @return
*/
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;
}
/**
* (非 Javadoc)
* @see javax.swing.table.JTableHeader#createDefaultRenderer()
*/
@Override
protected TableCellRenderer createDefaultRenderer() {
return new TableHeaderRenderer();
}
}
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 (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;
}
/**
* 获取Group的Y位置
*
* @param group
* @return
*/
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;
}
/**
* 获取Group的高度
*
* @param group
* @return
*/
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();
}
/**
* 增加Group
*
* @param group
*/
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);
}
/**
* 移除所有Group
*/
public void removeAllGroups() {
groups.clear();
}
/**
* 获取所有的Group
*
* @return
*/
public List<Group> getGroups() {
List<Group> list = new ArrayList<Group>();
list.addAll(groups);
return list;
}
/**
* 获取指定列上的Group
*
* @param columnIndex
* @return
*/
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;
}
/**
* 获取指定行上的所有Group
*
* @param rowIndex
* @return
*/
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;
}
/**
* 获取行数
*
* @return
*/
public int getRowCount() {
return this.rowCount;
}
/**
* @return Returns the columnCount.
*/
public int getColumnCount() {
return this.columnCount;
}
/*
* (非 Javadoc)
*
* @see javax.swing.table.JTableHeader#setTable(javax.swing.JTable)
*/
@Override
public void setTable(JTable table) {
super.setColumnModel(table.getColumnModel());
super.setTable(table);
}
/**
* 获取指定行列的Group
*
* @param row
* @param column
* @return
*/
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;
}
/**
* (非 Javadoc)
* @see javax.swing.table.JTableHeader#createDefaultRenderer()
*/
@Override
protected TableCellRenderer createDefaultRenderer() {
return new TableHeaderRenderer();
}
}
里面用到的TableHeaderRenderer, 没什么花头的, 贴出来看看
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;
import com.eplat.realty.view.Constants;
import com.eplat.realty.view.component.label.M2Label;
/**
* Created at 2006-9-5 16:02:46<br>
* 表头描述器
*
* @author Brad.Wu
* @version 1.0
*/
@SuppressWarnings( " serial " )
public class TableHeaderRenderer extends M2Label implements TableCellRenderer, Serializable {
/**
* Creates a default table cell renderer.
*/
public TableHeaderRenderer() {
setOpaque(true);
setHorizontalAlignment(JLabel.CENTER);
}
// implements javax.swing.table.TableCellRenderer
/**
* Returns the default table cell renderer.
*
* @param table the <code>JTable</code>
* @param value the value to assign to the cell at <code>[row, column]</code>
* @param isSelected true if cell is selected
* @param hasFocus true if cell has focus
* @param row the row of the cell to render
* @param column the column of the cell to render
* @return the default table cell renderer
*/
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;
}
/*
* The following methods are overridden as a performance measure to to prune code-paths are
* often called in the case of renders but which we know are unnecessary. Great care should be
* taken when writing your own renderer to weigh the benefits and drawbacks of overriding
* methods like these.
*/
/**
* Overridden for performance reasons. See the <a href="#override">Implementation Note</a> for
* more information.
*/
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();
}
/**
* Overridden for performance reasons. See the <a href="#override">Implementation Note</a> for
* more information.
*
* @since 1.5
*/
public void invalidate() {
}
/**
* Overridden for performance reasons. See the <a href="#override">Implementation Note</a> for
* more information.
*/
public void validate() {
}
/**
* Overridden for performance reasons. See the <a href="#override">Implementation Note</a> for
* more information.
*/
public void revalidate() {
}
/**
* Overridden for performance reasons. See the <a href="#override">Implementation Note</a> for
* more information.
*/
public void repaint(long tm, int x, int y, int width, int height) {
}
/**
* Overridden for performance reasons. See the <a href="#override">Implementation Note</a> for
* more information.
*/
public void repaint(Rectangle r) {
}
/**
* Overridden for performance reasons. See the <a href="#override">Implementation Note</a> for
* more information.
*
* @since 1.5
*/
public void repaint() {
}
/**
* Overridden for performance reasons. See the <a href="#override">Implementation Note</a> for
* more information.
*/
protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
// Strings get interned...
if (propertyName == "text") {
super.firePropertyChange(propertyName, oldValue, newValue);
}
}
/**
* Overridden for performance reasons. See the <a href="#override">Implementation Note</a> for
* more information.
*/
public void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) {
}
/**
* Sets the <code>String</code> object for the cell being rendered to <code>value</code>.
*
* @param value the string value for this cell; if value is <code>null</code> it sets the text
* value to an empty string
* @see JLabel#setText
*/
protected void setValue(Object value) {
setText((value == null) ? "" : value.toString());
}
/**
* A subclass of <code>DefaultTableCellRenderer</code> that implements <code>UIResource</code>.
* <code>DefaultTableCellRenderer</code> doesn't implement <code>UIResource</code> directly
* so that applications can safely override the <code>cellRenderer</code> property with
* <code>DefaultTableCellRenderer</code> subclasses.
* <p>
* <strong>Warning:</strong> Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is appropriate for short term
* storage or RMI between applications running the same version of Swing. As of 1.4, support for
* long term storage of all JavaBeans<sup><font size="-2">TM</font></sup> has been added to
* the <code>java.beans</code> package. Please see {@link java.beans.XMLEncoder}.
*/
public static class UIResource extends DefaultTableCellRenderer implements
javax.swing.plaf.UIResource {
}
}
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;
import com.eplat.realty.view.Constants;
import com.eplat.realty.view.component.label.M2Label;
/**
* Created at 2006-9-5 16:02:46<br>
* 表头描述器
*
* @author Brad.Wu
* @version 1.0
*/
@SuppressWarnings( " serial " )
public class TableHeaderRenderer extends M2Label implements TableCellRenderer, Serializable {
/**
* Creates a default table cell renderer.
*/
public TableHeaderRenderer() {
setOpaque(true);
setHorizontalAlignment(JLabel.CENTER);
}
// implements javax.swing.table.TableCellRenderer
/**
* Returns the default table cell renderer.
*
* @param table the <code>JTable</code>
* @param value the value to assign to the cell at <code>[row, column]</code>
* @param isSelected true if cell is selected
* @param hasFocus true if cell has focus
* @param row the row of the cell to render
* @param column the column of the cell to render
* @return the default table cell renderer
*/
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;
}
/*
* The following methods are overridden as a performance measure to to prune code-paths are
* often called in the case of renders but which we know are unnecessary. Great care should be
* taken when writing your own renderer to weigh the benefits and drawbacks of overriding
* methods like these.
*/
/**
* Overridden for performance reasons. See the <a href="#override">Implementation Note</a> for
* more information.
*/
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();
}
/**
* Overridden for performance reasons. See the <a href="#override">Implementation Note</a> for
* more information.
*
* @since 1.5
*/
public void invalidate() {
}
/**
* Overridden for performance reasons. See the <a href="#override">Implementation Note</a> for
* more information.
*/
public void validate() {
}
/**
* Overridden for performance reasons. See the <a href="#override">Implementation Note</a> for
* more information.
*/
public void revalidate() {
}
/**
* Overridden for performance reasons. See the <a href="#override">Implementation Note</a> for
* more information.
*/
public void repaint(long tm, int x, int y, int width, int height) {
}
/**
* Overridden for performance reasons. See the <a href="#override">Implementation Note</a> for
* more information.
*/
public void repaint(Rectangle r) {
}
/**
* Overridden for performance reasons. See the <a href="#override">Implementation Note</a> for
* more information.
*
* @since 1.5
*/
public void repaint() {
}
/**
* Overridden for performance reasons. See the <a href="#override">Implementation Note</a> for
* more information.
*/
protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
// Strings get interned...
if (propertyName == "text") {
super.firePropertyChange(propertyName, oldValue, newValue);
}
}
/**
* Overridden for performance reasons. See the <a href="#override">Implementation Note</a> for
* more information.
*/
public void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) {
}
/**
* Sets the <code>String</code> object for the cell being rendered to <code>value</code>.
*
* @param value the string value for this cell; if value is <code>null</code> it sets the text
* value to an empty string
* @see JLabel#setText
*/
protected void setValue(Object value) {
setText((value == null) ? "" : value.toString());
}
/**
* A subclass of <code>DefaultTableCellRenderer</code> that implements <code>UIResource</code>.
* <code>DefaultTableCellRenderer</code> doesn't implement <code>UIResource</code> directly
* so that applications can safely override the <code>cellRenderer</code> property with
* <code>DefaultTableCellRenderer</code> subclasses.
* <p>
* <strong>Warning:</strong> Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is appropriate for short term
* storage or RMI between applications running the same version of Swing. As of 1.4, support for
* long term storage of all JavaBeans<sup><font size="-2">TM</font></sup> has been added to
* the <code>java.beans</code> package. Please see {@link java.beans.XMLEncoder}.
*/
public static class UIResource extends DefaultTableCellRenderer implements
javax.swing.plaf.UIResource {
}
}
最重要的UI登场, 哈哈
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;
/**
* 可合并列头UI
*
* @author Brad.Wu
* @version 1.0
*/
public class GroupableTableHeaderUI extends BasicTableHeaderUI {
/*
* (非 Javadoc)
*
* @see javax.swing.plaf.basic.BasicTableHeaderUI#paint(java.awt.Graphics,
* javax.swing.JComponent)
*/
@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();
}
/**
* 描画指定行列
*
* @param g
* @param cellRect
* @param rowIndex
* @param columnIndex
*/
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);
}
/**
* 获取指定行列的描述组件
*
* @param rowIndex
* @param columnIndex
* @return
*/
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);
}
/**
* 获取列头的高度
*
* @return
*/
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());
}
/**
* Return the minimum size of the header. The minimum width is the sum of the minimum widths of
* each column (plus inter-cell spacing).
*/
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);
}
/**
* Return the preferred size of the header. The preferred height is the maximum of the preferred
* heights of all of the components provided by the header renderers. The preferred width is the
* sum of the preferred widths of each column (plus inter-cell spacing).
*/
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);
}
/**
* Return the maximum size of the header. The maximum width is the sum of the maximum widths of
* each column (plus inter-cell spacing).
*/
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);
}
}
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;
/**
* 可合并列头UI
*
* @author Brad.Wu
* @version 1.0
*/
public class GroupableTableHeaderUI extends BasicTableHeaderUI {
/*
* (非 Javadoc)
*
* @see javax.swing.plaf.basic.BasicTableHeaderUI#paint(java.awt.Graphics,
* javax.swing.JComponent)
*/
@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();
}
/**
* 描画指定行列
*
* @param g
* @param cellRect
* @param rowIndex
* @param columnIndex
*/
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);
}
/**
* 获取指定行列的描述组件
*
* @param rowIndex
* @param columnIndex
* @return
*/
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);
}
/**
* 获取列头的高度
*
* @return
*/
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());
}
/**
* Return the minimum size of the header. The minimum width is the sum of the minimum widths of
* each column (plus inter-cell spacing).
*/
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);
}
/**
* Return the preferred size of the header. The preferred height is the maximum of the preferred
* heights of all of the components provided by the header renderers. The preferred width is the
* sum of the preferred widths of each column (plus inter-cell spacing).
*/
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);
}
/**
* Return the maximum size of the header. The maximum width is the sum of the maximum widths of
* each column (plus inter-cell spacing).
*/
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);
}
}
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;
/**
* 合并列头测试
*
* @author Brad.Wu
* @version 1.0
*/
@SuppressWarnings( " serial " )
public class GroupableTableHeaderTest extends JFrame {
/**
* @param args
*/
public static void main(String[] args) {
GroupableTableHeaderTest test = new GroupableTableHeaderTest();
test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
test.setSize(800, 600);
test.setVisible(true);
}
private DefaultTableModel tableModel = new DefaultTableModel() {
/*
* (非 Javadoc)
*
* @see javax.swing.table.DefaultTableModel#getColumnCount()
*/
@Override
public int getColumnCount() {
return 6;
}
/*
* (非 Javadoc)
*
* @see javax.swing.table.DefaultTableModel#getRowCount()
*/
@Override
public int getRowCount() {
return 2;
}
};
private JTable table = new JTable(tableModel);
private JScrollPane scroll = new JScrollPane(table);
/**
* @throws HeadlessException
*/
public GroupableTableHeaderTest() 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);
}
}
import java.awt.HeadlessException;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
/**
* 合并列头测试
*
* @author Brad.Wu
* @version 1.0
*/
@SuppressWarnings( " serial " )
public class GroupableTableHeaderTest extends JFrame {
/**
* @param args
*/
public static void main(String[] args) {
GroupableTableHeaderTest test = new GroupableTableHeaderTest();
test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
test.setSize(800, 600);
test.setVisible(true);
}
private DefaultTableModel tableModel = new DefaultTableModel() {
/*
* (非 Javadoc)
*
* @see javax.swing.table.DefaultTableModel#getColumnCount()
*/
@Override
public int getColumnCount() {
return 6;
}
/*
* (非 Javadoc)
*
* @see javax.swing.table.DefaultTableModel#getRowCount()
*/
@Override
public int getRowCount() {
return 2;
}
};
private JTable table = new JTable(tableModel);
private JScrollPane scroll = new JScrollPane(table);
/**
* @throws HeadlessException
*/
public GroupableTableHeaderTest() 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);
}
}
最后
以上就是俊逸宝马为你收集整理的表头合并单元格. JTable Groupable TableHeader的全部内容,希望文章能够帮你解决表头合并单元格. JTable Groupable TableHeader所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复