jinlin
2025-03-18 d30e385951ce03335a5023f0775fd144da3c0b88
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package com.example.client.utils;
 
 
import javax.swing.*;
import javax.swing.plaf.basic.BasicTableHeaderUI;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableColumnModel;
import java.awt.*;
 
 
/**
 * 实现表头渲染UI,主要功能时画出表头的单元格
 * @author 雷锋
 * @Date 2019年5月27日
 */
public class ComplexHeaderUI extends BasicTableHeaderUI {
    private Object[][] headerRows;
    private JTable table;
    private int singleRowHeight;
    public ComplexHeaderUI(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 ));
    }
 
    /**
     * 重写BasicTableHeaderUI.paint的方法是最重要的部分
     */
    @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();
                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;
        }
 
        //得到一个单元格,起点坐标、宽度、高度
        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 = header.getColumnModel();
        for( int i = 0 ; i < mergeCellNum ; i++ ){
            width += colModel.getColumn( column + i ).getWidth();
        }
        return width;
    }
    //根据单元格所在列得到x轴坐标
    private int getCellX( int column ){
        int width = 0;
        TableColumnModel colModel = header.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;
    }
 
    //得到具有指定文本的标签
    private JLabel getComponent(String text){
        JLabel label = new JLabel(text, JLabel.CENTER);
        Font font = new Font("宋体", Font.BOLD, 23);
        label.setFont(font);
        label.setBorder(UIManager.getBorder("TableHeader.cellBorder"));
        return label;
    }
 
    private void paintCell(Graphics g, Rectangle cellRect , String text) {
        Component component = this.getComponent(text);
        rendererPane.paintComponent(g, component, header, cellRect.x, cellRect.y,
                cellRect.width, cellRect.height, true);
    }
 
}