zoukankan      html  css  js  c++  java
  • 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");
        for (short k = 10; k >= 5; k--) {
            font.setFontHeightInPoints(k);
            if (checkCellReasonable(cell, k)) {
                break;
            }
        }
        //解决单元格样式覆盖的问题
        CellStyle cStyle = book.createCellStyle();
        cStyle.cloneStyleFrom(cell.getCellStyle());
        cStyle.setWrapText(true);
        cStyle.setFont(font);
        cell.setCellStyle(cStyle);
    }
    
    /**
     * 校验单元格中的字体大小是否合理
     */
    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代码库》里介绍

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

  • 相关阅读:
    SAP C4C OBN(Object Based Navigation)不能工作的原因分析
    使用SAP C4C自定义BO association创建动态下拉列表
    如何使用SAP HANA Studio的PlanViz分析CDS view性能问题
    如何使用jMeter测试SAP OData服务并发访问时的性能
    OData服务在SAP CRM,Cloud for Customer和S/4HANA上的实现比较
    SAP UI5和Vue的数据双向绑定实现原理比较
    在SAP WebClient UI里显示倒数计时的UI
    【年度重磅】2020华为云社区年度技术精选合集,700页+免费下载!
    面试必问:如何实现Redis分布式锁
    聊聊架构模式的变迁:从分层架构到微服务架构
  • 原文地址:https://www.cnblogs.com/acm-bingzi/p/poiFontSizeAuto.html
Copyright © 2011-2022 走看看