如何使用合并单元格值大于单元格宽度的 Apache-POI 增加 excel 行的高度?

Posted

技术标签:

【中文标题】如何使用合并单元格值大于单元格宽度的 Apache-POI 增加 excel 行的高度?【英文标题】:How to increase the height of the excel row using Apache-POI having merged cell value greater than the cell width? 【发布时间】:2017-07-29 08:37:06 【问题描述】:

我正在使用 java 类创建一个大型 excel。 Excel 包含一个存储字符串的合并单元格。字符串的长度非常大,我正在动态获取这个字符串。我需要增加合并单元格的高度,以便完整的字符串适合该单元格。我尝试过使用“换行文本”,它会换行文本,但不会增加合并单元格的高度,因为在 excel 中看不到完整的字符串。 我正在使用的 Java 类是:

    XSSF 工作簿 XSSFSheet XSSFRow XSSFCell XSSFCellStype

以及其他必需的依赖类。 有没有办法根据单元格值增加合并单元格的高度。

【问题讨论】:

计算所需高度,然后使用XSSFRowsetHeight 方法之一。如何计算所需高度?嗯,这就是挑战。 Excel (Microsoft) 本身并没有解决这个问题,因为Excel 不可能为合并的单元格设置“最佳高度”。 【参考方案1】:

让您了解如何计算所需的行高。

我们可以使用Sheet.getColumnWidth(int) 来获取以字符宽度为单位的列宽。但这并不准确,因为它仅适用于数字字形:1、2、3、4、5、6、7、8、9、0。在真正的字体中,字形(.、|、l、...)需要的宽度要小得多。因此,由于文本中使用了宽度较小的字形,因此该结果将更加不准确。

我们可能会修正字符中的列宽。我用 5/4。但这在很大程度上取决于所使用的语言。

然后我们可以计算所需的行数,然后通过获取用于一行的默认行高并将其乘以所需的行数来获得所需的行高。

import java.io.FileOutputStream;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.ss.util.CellRangeAddress;

public class CreateExcelCellWrapText 

 public static void main(String[] args) throws Exception 
  XSSFWorkbook workbook = new XSSFWorkbook();

  CellStyle cellstyle = workbook.createCellStyle();
  cellstyle.setWrapText(true);

  Sheet sheet = workbook.createSheet();

//__________________________not merged = height is auto sized

  Row row = sheet.createRow(0);

  Cell cell = row.createCell(2);
  cell.setCellValue("String cell content\nhaving line wrap.");
  cell.setCellStyle(cellstyle);

//__________________________merged = height is not auto sized

  row = sheet.createRow(2);

  cell = row.createCell(2);
  cell.setCellValue("String cell content\nhaving line wrap.");
  cell.setCellStyle(cellstyle);

  CellRangeAddress cellRangeAddress = new CellRangeAddress(2, 2, 2, 3);
  sheet.addMergedRegion(cellRangeAddress);

//__________________________merged with calculated height

  row = sheet.createRow(4);

  String text = "String cell content\nhaving line wrap.\nIt has new line marks and then a long text without new line marks.\nFollowed by short text part.\n\n\nGreetings";

  cell = row.createCell(2);
  cell.setCellValue(text);
  cell.setCellStyle(cellstyle);

  cellRangeAddress = new CellRangeAddress(4, 4, 2, 3);
  sheet.addMergedRegion(cellRangeAddress);

  //get the column width in character widths for the merged columns
  //this is not really accurate since it only is for number glyphs: 1,2,3,4,5,6,7,8,9,0
  //in true type fonts there are glyps (., |, l, ...) which need much less width
  int colwidthinchars = (sheet.getColumnWidth(2) + sheet.getColumnWidth(3)) / 256;
System.out.println(colwidthinchars);
  //correct the colwidthinchars by a factor 5/4 (highly dependent on the language used)
  colwidthinchars = Math.round(colwidthinchars * 5f/4f);
System.out.println(colwidthinchars);

  //calculate the needed rows dependent on the text and the column width in character widths
  String[] chars = text.split("");
  int neededrows = 1;
  int counter = 0;
  for (int i = 0; i < chars.length; i++) 
   counter++;
   if (counter == colwidthinchars) 
System.out.println("new line because of charcter count");
    neededrows++;
    counter = 0;
    else if ("\n".equals(chars[i])) 
System.out.println("new line because of new line mark");
    neededrows++;
    counter = 0;
   
  

System.out.println(neededrows);

  //get default row height
  float defaultrowheight = sheet.getDefaultRowHeightInPoints();
System.out.println(defaultrowheight);

  row.setHeightInPoints(neededrows * defaultrowheight);

  workbook.write(new FileOutputStream("CreateExcelCellWrapText.xlsx"));
  workbook.close();
 

这是因为使用了默认字体和字体大小。当使用不同的字体和不同的字体大小时,挑战会增加到无穷大;-)。

请参阅 How to get the needed height of a multi line rich-text field (any font, any font size) having defined width using Java? 以获取在 JTextPane 中呈现格式化文本以获得首选高度的示例。

【讨论】:

当我们从默认值更改字体或高度时不起作用此代码仅适用于默认单元格属性,当我再次对单元格(如字体或高度)进行很少更改时,我我遇到了同样的问题,我不能一直将单元格属性保持为默认值。 解决这个问题的唯一方法是在图形环境中的某个文本框中呈现格式化文本。但是使用 Java 并没有很好的工作示例。例如,XSLFTextShape.resizeToFitText 正在这样做。但是使用默认值之外的字体和字体大小的结果也不是很令人满意。因此,您的问题可能是“如何使用 Java 获得具有定义宽度的多行富文本字段(任何字体、任何字体大小)所需的高度?” 你的代码 sn-p 解决了我 60% 的问题。我也尝试了 awt 中存在的图形类,但没有得到任何好的工作示例。我会尝试 XSLFTextShape.resizeToFitText 看看它是否能解决问题。当我解决此问题时,将在此处通过示例对其进行更新。感谢您的帮助:) @FREEVARUN:我试过XSLFTextShape.resizeToFitText,但没有得到令人满意的结果,如上所述。但是你自己试试。如果我有时间,我会问“如何使用 Java 获得具有定义宽度的多行富文本字段(任何字体、任何字体大小)所需的高度?”这里作为一个自己的问题。但你也可以这样做。 There is a similiar question already. 但这是关于渲染 html

以上是关于如何使用合并单元格值大于单元格宽度的 Apache-POI 增加 excel 行的高度?的主要内容,如果未能解决你的问题,请参考以下文章

根据单元格值合并范围内的单元格,但最后一个单元格没有被合并

如何合并行中重复的单元格值?我的代码忽略了一些重复的值

Python-openpyxl对excel取消/合并单元格,以及修改单元格值

如何获取gridview单元格的值

nodejs读取excel时如何判断合并的单元格

如何使用apache poi 3.1获取公式单元格值(数据)