JTable合并单元格
JTable单元格合并
合并指定的一列或几列中行连续相同的单元格的值。
效果如下
以下代码根据翼辉博客(http://blog.csdn.net/tjh666/archive/2007/06/29/1671113.aspx)JTable合并单元格代码改编
CombineData.java
import java.util.ArrayList; import java.util.HashMap; import java.util.List; public class CombineData { public ArrayList<Integer> combineColumns = new ArrayList<Integer>();//用于保存需要合并的列号 private String[][] datas;//table的数据,用来计算合并的单元格 private ArrayList<HashMap<Integer, Integer>> rowPoss; private ArrayList<HashMap<Integer, Integer>> rowCounts; public CombineData() { } public CombineData(String[][] datas, int... combineColumns) { this.datas = datas; for (int i = 0; i < combineColumns.length; i++) { if (combineColumns[i] < 0) { continue; } this.combineColumns.add(combineColumns[i]); } process(); } public CombineData(String[][] datas, List<Integer> combineColumns) { this.datas = datas; for (Integer column : combineColumns) { if (column < 0) { continue; } this.combineColumns.add(column); } process(); } public void initData(String[][] datas, int... combineColumns) { this.datas = datas; this.combineColumns.clear(); for (int i = 0; i < combineColumns.length; i++) { if (combineColumns[i] < 0) { continue; } this.combineColumns.add(combineColumns[i]); } process(); } public void initData(String[][] datas, List<Integer> combineColumns) { this.datas = datas; this.combineColumns.clear(); for (Integer column : combineColumns) { if (column < 0) { continue; } this.combineColumns.add(column); } process(); } private void process() { rowPoss = new ArrayList<HashMap<Integer, Integer>>(); rowCounts = new ArrayList<HashMap<Integer, Integer>>(); for (Integer integer : combineColumns) { HashMap<Integer, Integer> rowPos = new HashMap<Integer, Integer>(); HashMap<Integer, Integer> rowCount = new HashMap<Integer, Integer>(); String pre = ""; int count = 0; int start = 0; for (int i = 0; i < datas.length; i++) { String[] data = datas[i]; if (pre.equals(data[integer])) { count++; } else { rowCount.put(start, count); pre = data[integer]; count = 1; start = i; } rowPos.put(i, start); } rowCount.put(start, count); rowPoss.add(rowPos); rowCounts.add(rowCount); } } /** * 返回table中row行column列单元格所跨行数 */ public int span(int row, int column) { int index = combineColumns.lastIndexOf(column); if (index != -1) { return rowCounts.get(index).get(rowPoss.get(index).get(row)); } else { return 1; } } /** * 返回table中row行column列单元格所在的合并单元格的起始行位置 */ public int visibleCell(int row, int column) { int index = combineColumns.lastIndexOf(column); if ((index != -1) && row > -1) { return rowPoss.get(index).get(row); } else { return row; } } }
CombineTable.java
import javax.swing.*; import java.awt.*; import javax.swing.table.TableColumn; import javax.swing.table.TableModel; public class CombineTable extends JTable { public CombineData combineData; public CombineTable(TableModel tableModel) { super(tableModel); super.setUI(new CombineTableUI()); } public CombineTable(CombineData combineData, TableModel tableModel) { super(tableModel); this.combineData = combineData; for (Integer column : combineData.combineColumns) { TableColumn tableColumn = super.columnModel.getColumn(column); tableColumn.setCellRenderer(new CombineColumnRender()); } super.setUI(new CombineTableUI()); } public void setCombineData(CombineData combineData) { this.combineData = combineData; for (Integer column : combineData.combineColumns) { TableColumn tableColumn = super.columnModel.getColumn(column); tableColumn.setCellRenderer(new CombineColumnRender()); } } @Override public Rectangle getCellRect(int row, int column, boolean includeSpacing) { // required because getCellRect is used in JTable constructor if (combineData == null) { return super.getCellRect(row, column, includeSpacing); } // add widths of all spanned logical cells int sk = combineData.visibleCell(row, column); //Rectangle r1 = super.getCellRect(row, sk, includeSpacing); Rectangle rect1 = super.getCellRect(sk, column, includeSpacing); if (combineData.span(sk, column) != 1) { for (int i = 1; i < combineData.span(sk, column); i++) { //r1.width += getColumnModel().getColumn(sk + i).getWidth(); rect1.height += this.getRowHeight(sk + i); } } return rect1; } @Override public int rowAtPoint(Point p) { int column = super.columnAtPoint(p); // -1 is returned by columnAtPoint if the point is not in the table if (column < 0) { return column; } int row = super.rowAtPoint(p); return combineData.visibleCell(row, column); } @Override public boolean isCellEditable(int row, int column) { if (combineData.combineColumns.contains(column)) { return false; } return super.isCellEditable(row, column); } @Override public boolean isCellSelected(int row, int column) { if (combineData.combineColumns.contains(column)) { return false; } return super.isCellSelected(row, column); } }
CombineTableUI.java
import javax.swing.table.*; import javax.swing.plaf.basic.*; import java.awt.*; import javax.swing.*; class CombineTableUI extends BasicTableUI { @Override public void paint(Graphics g, JComponent c) { Rectangle r = g.getClipBounds(); rendererPane.removeAll(); int firstCol = table.columnAtPoint(new Point(r.x, 0)); int lastCol = table.columnAtPoint(new Point(r.x + r.width, 0)); // -1 is a flag that the ending point is outside the table if (lastCol < 0) { lastCol = table.getColumnCount() - 1; } for (int i = firstCol; i <= lastCol; i++) { paintCol(i, g); } paintGrid(g, 0, table.getRowCount() - 1, 0, table.getColumnCount() - 1); } private void paintCol(int col, Graphics g) { Rectangle r = g.getClipBounds(); for (int i = 0; i < table.getRowCount(); i++) { Rectangle r1 = table.getCellRect(i, col, true); if (r1.intersects(r)) // at least a part is visible { int sk = ((CombineTable) table).combineData.visibleCell(i, col); paintCell(sk, col, g, r1); // increment the column counter i += ((CombineTable) table).combineData.span(sk, col) - 1; } } } private void paintCell(int row, int column, Graphics g, Rectangle area) { int verticalMargin = table.getRowMargin(); int horizontalMargin = table.getColumnModel().getColumnMargin(); area.setBounds(area.x + horizontalMargin / 2, area.y + verticalMargin / 2, area.width - horizontalMargin, area.height - verticalMargin); if (table.isEditing() && table.getEditingRow() == row && table.getEditingColumn() == column) { Component component = table.getEditorComponent(); component.setBounds(area); component.validate(); } else { TableCellRenderer renderer = table.getCellRenderer(row, column); Component component = table.prepareRenderer(renderer, row, column); if (component.getParent() == null) { rendererPane.add(component); } rendererPane.paintComponent(g, component, table, area.x, area.y, area.width, area.height, true); } } private void paintGrid(Graphics g, int rMin, int rMax, int cMin, int cMax) { g.setColor(table.getGridColor()); Rectangle minCell = table.getCellRect(rMin, cMin, true); Rectangle maxCell = table.getCellRect(rMax, cMax, true); Rectangle damagedArea = minCell.union(maxCell); if (table.getShowHorizontalLines()) { CombineData cMap = ((CombineTable) table).combineData; for (int row = rMin; row <= rMax; row++) { for (int column = cMin; column <= cMax; column++) { Rectangle cellRect = table.getCellRect(row, column, true); if (cMap.combineColumns.contains(column)) { int visibleCell = cMap.visibleCell(row, column); int span = cMap.span(row, column); if (span > 1 && row < visibleCell + span - 1) { } else { g.drawLine(cellRect.x, cellRect.y + cellRect.height - 1, cellRect.x + cellRect.width - 1, cellRect.y + cellRect.height - 1); } } else { g.drawLine(cellRect.x, cellRect.y + cellRect.height - 1, cellRect.x + cellRect.width - 1, cellRect.y + cellRect.height - 1); } } } } if (table.getShowVerticalLines()) { TableColumnModel cm = table.getColumnModel(); int tableHeight = damagedArea.y + damagedArea.height; int x; if (table.getComponentOrientation().isLeftToRight()) { x = damagedArea.x; for (int column = cMin; column <= cMax; column++) { int w = cm.getColumn(column).getWidth(); x += w; g.drawLine(x - 1, 0, x - 1, tableHeight - 1); } } else { x = damagedArea.x; for (int column = cMax; column >= cMin; column--) { int w = cm.getColumn(column).getWidth(); x += w; g.drawLine(x - 1, 0, x - 1, tableHeight - 1); } } } } }
CombineColumnRender.java
import java.awt.Component; import javax.swing.JTable; import javax.swing.table.DefaultTableCellRenderer; /** * 设置需要合并的列的单元格不能被选中,不能聚焦 * @author hualun-alan */ class CombineColumnRender extends DefaultTableCellRenderer { @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { CombineTable cTable = (CombineTable) table; if (cTable.combineData.combineColumns.contains(column)) { hasFocus = false; } return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); } }
Test.java
import java.util.ArrayList; import javax.swing.*; import javax.swing.table.*; public class Test { public static void main(String args[]) { JFrame jf = new JFrame("Cell Combine Table"); JTable cTable = getTable1(); jf.getContentPane().add(new JScrollPane(cTable)); jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); jf.setSize(500, 500); jf.setVisible(true); } private static CombineTable getTable1() { String[][] datas = new String[10][6]; for (int i = 0; i < datas.length; i++) { String[] data = datas[i]; for (int j = 0; j < data.length; j++) { data[j] = ""; } data[0] = String.valueOf((int) (i / 3)); } ArrayList<Integer> combineColumns = new ArrayList<Integer>(); combineColumns.add(0); CombineData m = new CombineData(datas, combineColumns); DefaultTableModel tm = new DefaultTableModel(datas, new String[]{"1", "2", "3", "4", "5"}); CombineTable cTable = new CombineTable(m, tm); TableColumn column = cTable.getColumnModel().getColumn(0); column.setCellRenderer(new CombineColumnRender()); column.setWidth(50); column.setMaxWidth(50); column.setMinWidth(50); cTable.setCellSelectionEnabled(true); return cTable; } private static CombineTable getTable2() { String[][] datas = new String[10][6]; for (int i = 0; i < datas.length; i++) { String[] data = datas[i]; for (int j = 0; j < data.length; j++) { data[j] = ""; } data[0] = String.valueOf((int) (i / 4)); data[1] = String.valueOf((int) (i / 2)); } CombineData m = new CombineData(datas, 0, 1); DefaultTableModel tm = new DefaultTableModel(datas, new String[]{"1", "2", "3", "4", "5"}); CombineTable cTable = new CombineTable(m, tm); TableColumnModel columnModel = cTable.getColumnModel(); for (Integer integer : m.combineColumns) { TableColumn column = columnModel.getColumn(integer); column.setCellRenderer(new CombineColumnRender()); column.setWidth(50); column.setMaxWidth(50); column.setMinWidth(50); } cTable.setCellSelectionEnabled(true); return cTable; } }