| | |
| | | * @author 雷锋 |
| | | * @Date 2019年5月27日 |
| | | */ |
| | | import javax.swing.*; |
| | | import javax.swing.table.TableCellRenderer; |
| | | import javax.swing.table.TableColumnModel; |
| | | import java.awt.*; |
| | | import java.awt.event.MouseEvent; |
| | | |
| | | public class ComplexTableUI extends BasicTableUI { |
| | | private Object[][] headerRows; |
| | | private Object[][] headerRows; // 表头数据,用于判断合并逻辑 |
| | | private JTable table; |
| | | private int singleRowHeight; |
| | | public ComplexTableUI(Object[][] headerRows,JTable table){ |
| | | private int singleRowHeight; // 每行的高度 |
| | | private int headerHeight; // 表头的总高度 |
| | | |
| | | public ComplexTableUI(Object[][] headerRows, JTable table) { |
| | | this.headerRows = headerRows; |
| | | this.table = table; |
| | | //获取单行的高度,不能使用header.getHeight()获取高度,因为此时表头还没初始化完毕,获取出来的高度是0 |
| | | this.singleRowHeight = table.getRowHeight(); |
| | | // System.out.println(table.getRowHeight()); |
| | | |
| | | JTableHeader tableHeader = table.getTableHeader(); |
| | | //设置表头不允许拖动 、由于合并了单元格,拖动之后会乱 |
| | | tableHeader.setReorderingAllowed(false); |
| | | //设置表头整体高度、宽度 |
| | | tableHeader.setPreferredSize(new Dimension(table.getWidth(), singleRowHeight * headerRows.length )); |
| | | this.singleRowHeight = table.getRowHeight(); // 获取单行高度 |
| | | this.headerHeight = singleRowHeight * headerRows.length; // 计算表头总高度 |
| | | } |
| | | |
| | | /** |
| | | * 重写BasicTableHeaderUI.paint的方法是最重要的部分 |
| | | */ |
| | | @Override |
| | | public void installUI(JComponent c) { |
| | | super.installUI(c); |
| | | // 禁用列的拖动,因为合并单元格可能导致布局混乱 |
| | | table.getTableHeader().setReorderingAllowed(false); |
| | | } |
| | | |
| | | @Override |
| | | public void paint(Graphics g, JComponent c) { |
| | | for( int row = 0 ; row < headerRows.length ; row++ ){ |
| | | Object[] headerRow = headerRows[row]; |
| | | for( int col = 0 ; col < headerRow.length ; col++ ){ |
| | | Object cell = headerRow[col]; |
| | | //如果单元格为合并类单元格、获取其上方是X合并类单元格 + 左边是Y合并类单元格,那么该单元格不需要在窗口展示 |
| | | if( cell == ComplexTable.mergeCellX || cell == ComplexTable.mergeCellY || ( col > 0 && row > 0 && headerRow[col - 1] == ComplexTable.mergeCellY && headerRows[row-1][col] == ComplexTable.mergeCellX ) ) |
| | | continue; |
| | | Rectangle rect = this.getCellRect(row, col); |
| | | String text = cell == null ? "" : cell.toString(); |
| | | super.paint(g, c); // 绘制默认的表格内容 |
| | | |
| | | // 遍历表格主体的每一行和每一列 |
| | | for (int row = 0; row < table.getRowCount(); row++) { |
| | | for (int col = 0; col < table.getColumnCount(); col++) { |
| | | if (isMergedCell(row, col)) { |
| | | continue; // 跳过被合并的单元格 |
| | | } |
| | | |
| | | // 获取单元格的绘制区域 |
| | | Rectangle rect = getCellRect(row, col); |
| | | // 获取单元格内容 |
| | | Object value = table.getValueAt(row, col); |
| | | String text = value == null ? "" : value.toString(); |
| | | |
| | | // 绘制单元格 |
| | | paintCell(g, rect, text); |
| | | } |
| | | } |
| | | |
| | | } |
| | | |
| | | /** |
| | | * 获取当前单元格需要占多少个单位,比如此时的row+1行col列的值=mergeCell,那么说明当前单元格需要占2行 |
| | | * @param row |
| | | * @param col |
| | | * @return |
| | | * 判断单元格是否被合并 |
| | | */ |
| | | private Rectangle getCellRect(int row , int col){ |
| | | int mergeRowNum = 1; |
| | | int nextRow = row; |
| | | //判断出y轴方向合并了几行 |
| | | while( ++nextRow < headerRows.length ){ |
| | | Object nextRowCell = headerRows[nextRow][col]; |
| | | if( nextRowCell == ComplexTable.mergeCellY ) |
| | | mergeRowNum++; |
| | | else |
| | | break; |
| | | } |
| | | int mergeCellNum = 1; |
| | | int nextCol = col; |
| | | Object[] headerRow = headerRows[row]; |
| | | //判断x轴方向合并了几列 |
| | | while( ++nextCol < headerRow.length ){ |
| | | Object nextCell = headerRow[nextCol]; |
| | | if( nextCell == ComplexTable.mergeCellX ) |
| | | mergeCellNum++; |
| | | else |
| | | break; |
| | | private boolean isMergedCell(int row, int col) { |
| | | // 示例:假设合并逻辑基于表格主体数据 |
| | | Object cellValue = table.getValueAt(row, col); |
| | | return cellValue == ComplexTable.mergeCellX || cellValue == ComplexTable.mergeCellY; |
| | | } |
| | | |
| | | /** |
| | | * 获取单元格的绘制区域 |
| | | */ |
| | | private Rectangle getCellRect(int row, int col) { |
| | | // 获取默认单元格区域 |
| | | Rectangle rect = table.getCellRect(row, col, false); |
| | | |
| | | // 调整 y 坐标,考虑表头高度 |
| | | rect.y += headerHeight; |
| | | |
| | | // 如果需要合并单元格,调整区域大小 |
| | | if (isMergedCell(row, col)) { |
| | | int mergeRowNum = getMergeRowNum(row, col); |
| | | int mergeColNum = getMergeColNum(row, col); |
| | | rect.height = getCellHeight(mergeRowNum); |
| | | rect.width = getCellWidth(col, mergeColNum); |
| | | } |
| | | |
| | | //得到一个单元格,起点坐标、宽度、高度 |
| | | Rectangle rect = new Rectangle(); |
| | | rect.height = this.getCellHeight(mergeRowNum); |
| | | rect.width = this.getCellWidth( col , mergeCellNum); |
| | | rect.y = this.getCellY(row); |
| | | rect.x = this.getCellX( col ); |
| | | return rect; |
| | | } |
| | | |
| | | //根据合并行数得到单元格的高度 |
| | | private int getCellHeight( int mergeRowNum ){ |
| | | int height = 0; |
| | | for( int i = 0 ; i < mergeRowNum ; i++ ) |
| | | height += singleRowHeight; |
| | | return height; |
| | | } |
| | | //根据合并列数得到单元格宽度 |
| | | private int getCellWidth( int column , int mergeCellNum ){ |
| | | int width = 0; |
| | | TableColumnModel colModel = table.getColumnModel(); |
| | | for( int i = 0 ; i < mergeCellNum ; i++ ){ |
| | | width += colModel.getColumn( column + i ).getWidth(); |
| | | /** |
| | | * 获取合并的行数 |
| | | */ |
| | | private int getMergeRowNum(int row, int col) { |
| | | int mergeRowNum = 1; |
| | | for (int nextRow = row + 1; nextRow < table.getRowCount(); nextRow++) { |
| | | Object nextRowCell = table.getValueAt(nextRow, col); |
| | | if (nextRowCell == ComplexTable.mergeCellY) { |
| | | mergeRowNum++; |
| | | } else { |
| | | break; |
| | | } |
| | | } |
| | | return width; |
| | | } |
| | | //根据单元格所在列得到x轴坐标 |
| | | private int getCellX( int column ){ |
| | | int width = 0; |
| | | TableColumnModel colModel = table.getColumnModel(); |
| | | for( int i = 0 ; i < column ; i++ ){ |
| | | width += colModel.getColumn( i ).getWidth(); |
| | | } |
| | | return width; |
| | | } |
| | | //根据单元格所在行得到y轴坐标 |
| | | private int getCellY( int row ){ |
| | | int height = 0; |
| | | for( int i = 0 ; i < row ; i++ ){ |
| | | height += singleRowHeight; |
| | | } |
| | | return height; |
| | | return mergeRowNum; |
| | | } |
| | | |
| | | //得到具有指定文本的标签 |
| | | private JLabel getComponent(String text){ |
| | | /** |
| | | * 获取合并的列数 |
| | | */ |
| | | private int getMergeColNum(int row, int col) { |
| | | int mergeColNum = 1; |
| | | for (int nextCol = col + 1; nextCol < table.getColumnCount(); nextCol++) { |
| | | Object nextCell = table.getValueAt(row, nextCol); |
| | | if (nextCell == ComplexTable.mergeCellX) { |
| | | mergeColNum++; |
| | | } else { |
| | | break; |
| | | } |
| | | } |
| | | return mergeColNum; |
| | | } |
| | | |
| | | /** |
| | | * 根据合并行数计算单元格高度 |
| | | */ |
| | | private int getCellHeight(int mergeRowNum) { |
| | | return mergeRowNum * singleRowHeight; |
| | | } |
| | | |
| | | /** |
| | | * 根据合并列数计算单元格宽度 |
| | | */ |
| | | private int getCellWidth(int col, int mergeColNum) { |
| | | TableColumnModel colModel = table.getColumnModel(); |
| | | int width = 0; |
| | | for (int i = 0; i < mergeColNum; i++) { |
| | | width += colModel.getColumn(col + i).getWidth(); |
| | | } |
| | | return width; |
| | | } |
| | | |
| | | /** |
| | | * 绘制单元格 |
| | | */ |
| | | private void paintCell(Graphics g, Rectangle rect, String text) { |
| | | Component component = getComponent(text); |
| | | rendererPane.paintComponent(g, component, table, rect.x, rect.y, |
| | | rect.width, rect.height, true); |
| | | } |
| | | |
| | | /** |
| | | * 创建用于绘制的组件 |
| | | */ |
| | | private JLabel getComponent(String text) { |
| | | JLabel label = new JLabel(text, JLabel.CENTER); |
| | | Font font = new Font("宋体", Font.BOLD, 23); |
| | | Font font = new Font("宋体", Font.PLAIN, 16); |
| | | label.setFont(font); |
| | | label.setBorder(UIManager.getBorder("TableHeader.cellBorder")); |
| | | label.setBorder(UIManager.getBorder("Table.cellBorder")); |
| | | return label; |
| | | } |
| | | |
| | | private void paintCell(Graphics g, Rectangle cellRect , String text) { |
| | | Component component = this.getComponent(text); |
| | | rendererPane.paintComponent(g, component, table, cellRect.x, cellRect.y, |
| | | cellRect.width, cellRect.height, true); |
| | | } |
| | | |
| | | } |
| | | |
| | | } |