合并指定的一列或几列中行连续相同的单元格的值。

效果如下

table-1

table-2

以下代码根据翼辉博客(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, introw, 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;
    }
}

发表评论

邮箱地址不会被公开。 必填项已用*标注