POI如何自动调整Excel单元格中字体的大小

Posted 阿丙的博客园

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POI如何自动调整Excel单元格中字体的大小相关的知识,希望对你有一定的参考价值。

问题

  目的是要将Excel中的文字全部显示出来,可以设置对齐格式为【缩小字体填充】,但是这样的话只能展示出一行数据,字体会变得很小。还有一种办法,设置对齐格式为【自动换行】,然后让单元格中的字体自动调整大小。

  我的实现思路是,设置单元格中的字体大小,最大10号字,最小5号字,判断优先使用大的字体;如果最小的5号字也放不下,那就只能调整模板了。关键点就是判断当前字号能否将内容完全展示在单元格中。

  需要提前说明一点,我的这个方法是不精确的算法,excel设置字体的时候太强大了,不同的字体的字间距、行间距都会不同。

 

关键点

  判断字体大小是否合理的思路:

  1、计算出单元格的总宽度、总高度
  2、计算出其中的内容的总长度,不同的字号,长度是不同的
  3、内容总长度除以单元格宽度,得出实际上一共有多少行数据 x
  4、单元格的总高度除以内字体的高度,得出能展示出来的数据有多少行 y
  5、如果 y>=x ,那么表示所有的数据都能展示出来

  这个判断单元格中的字体大小是否合理的思路也不难,难的是如何获取到需要的参数。

 

注意点

  1、设置单元格字体大小的方法是:font.setFontHeightInPoints(k),但是获取字体宽度和高度的方法并不精确,因为字体间会有字间距,换行以后行之间也有间距,所以这个算法并不精确。
    这个例子中,我的获取字体高度的方法是直接取 k,获取字体宽度的方法是 k*2

  2、在上诉关键点的第5步中,本来我的想法是 y向下取整, x向上取整,然后再进行比较。但是测试后发现,设置的字体都会偏小。 直接取y>=x,结果反而更合理些。

  3、进行相除运算,单位必须相同。POI中Point(坐标点)和Pixel(像素点)的大小关系,我在之前的文章有介绍过,引用结论,获取行高的像素值的方法就是: (row.getHeightInPoints() / 72) * 96

 

代码实例

  样例中的单元格是合并单元格,起始坐标 (3,5),结束坐标 (3,8)

public static void main(String[] args) {

    try (InputStream is = new FileInputStream("E:\\test1.xls");
         Workbook book = new HSSFWorkbook(is);) {

        Cell cell = book.getSheetAt(0).getRow(3).getCell(5);
        String str = "一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十";
        cell.setCellValue(str);

        setFontSize(book, cell);

        File f = new File("E:\\test2.xls");
        FileOutputStream out = new FileOutputStream(f);
        book.write(out);
    } catch (IOException e) {
        //return;
    }
}

/**
 * 设置单元格字体大小
 */
private static void setFontSize(Workbook book, Cell cell) {
    Font font = book.createFont();
    font.setFontName("EUDC");
    cell.getCellStyle().setWrapText(true);
    cell.getCellStyle().setFont(font);
    for (short k = 10; k >= 5; k--) {
        font.setFontHeightInPoints(k);
        if (checkCellReasonable(cell, k)) {
            break;
        }
    }
}

/**
 * 校验单元格中的字体大小是否合理
 */
private static boolean checkCellReasonable(Cell cell, short fontSize) {
    int sum = cell.getStringCellValue().length();
    double cellWidth = getTotalWidth(cell);
    double fontWidth = (double) fontSize / 72 * 96 * 2;
    double cellHeight = cell.getRow().getHeightInPoints();
    double rows1 = fontWidth * sum / cellWidth;
    double rows2 = cellHeight / fontSize;
    return rows2 >= rows1;
}

/**
 * 获取单元格的总宽度(单位:像素)
 */
private static double getTotalWidth(Cell cell) {
    int x = getColNum(cell.getSheet(), cell.getRowIndex(), cell.getColumnIndex());
    double totalWidthInPixels = 0;
    for (int i = 0; i < x; i++) {
        totalWidthInPixels += cell.getSheet().getColumnWidthInPixels(i + cell.getColumnIndex());
    }
    return totalWidthInPixels;
}

/**
 * 获取单元格的列数,如果是合并单元格,就获取总的列数
 */
private static int getColNum(Sheet sheet, int row, int column) {
    int sheetMergeCount = sheet.getNumMergedRegions();
    //判断该单元格是否是合并区域的内容
    for (int i = 0; i < sheetMergeCount; i++) {
        CellRangeAddress ca = sheet.getMergedRegion(i);
        int firstColumn = ca.getFirstColumn();
        int lastColumn = ca.getLastColumn();
        int firstRow = ca.getFirstRow();
        int lastRow = ca.getLastRow();

        if (row >= firstRow && row <= lastRow && column >= firstColumn && column <= lastColumn) {
            return lastColumn - firstColumn + 1;
        }
    }
    return 1;
}

 

  其中,获取单元格总宽度的方法getTotalWidth(Cell cell),有更简单的方法,在《我的POI代码库》里介绍

 

原创文章,欢迎转载,转载请注明出处!

以上是关于POI如何自动调整Excel单元格中字体的大小的主要内容,如果未能解决你的问题,请参考以下文章

POI生成excel如何实现自动调整行高

如何让excel表格自动适应文字长度?

为啥我的Excel的字体大小更改不了呢?

POI生成excel如何实现自动调整行高

C#/VB.NET 在Excel单元格中应用多种字体格式

求 java用poi包读取excel单元格长度宽度的方法