如何在NPOI中实现宽度自适应和高度自适应

转自:  blog.csdn.net/echoshinian100/article/details/38540321

  由于系统需要在网页上导 出Excel文件,最近花了一段时间去学习NPOI插件。通过NPOI插件在服务端来生成Excel文件流并下载到本地。NPOI实际上和Excel一毛 钱关系都没有,它只是完全破译了Excel文件的存储格式,并用C#来生成同样的格式从而被识别为Excel文件。

    NPOI和Excel VBA相比优点很多,首先是Excel VBA中的对象太多,而且是基于Visual Basic语言来书写,而且是在Excel中进行编程开发,IDE十分原始,没有任何的智能感知和代码着色功能。(最近可以在VS进行VBA开发了得意) 抛开这些不说,微软官方是不建议在服务器端来操作Excel的。原话好像是不建议用asp,asp.net等无人的方式来使用Excel。而且最要命的是 VBA方式来操作Excel后,其进程很难释放干净。在桌面端生成一两个文件倒无所谓,后台多跑两个Excel也不是啥大事。但在服务器端多用户操作,很 有可能会出现死锁等问题。

     NPOI是从JAVA的POI移植而来,使用方式非常自然。

     但是我发现在NPOI中实现宽度和高度自适应很难,宽度和高度自适应,说简单点就是如何让宽度和高度刚刚好。不让内容被遮挡,使用者在下载表格后不需要手工调整。

     NPOI有一个宽度自适应属性,可惜只对英文和数字有效,对汉字无效。后来在一个台湾博客上发现了一段解决代码,我稍加改造后如下:

  1. <span style="font-family:Microsoft YaHei;font-size:14px;">    for (int columnNum = 0; columnNum <= 26; columnNum++)  
  2.             {  
  3.                 int columnWidth = ffSheet.GetColumnWidth(columnNum) / 256;//获取当前列宽度  
  4.                 for (int rowNum = 1; rowNum <= ffSheet.LastRowNum; rowNum++)//在这一列上循环行  
  5.                 {  
  6.                     IRow currentRow = ffSheet.GetRow(rowNum);  
  7.                     ICell currentCell = currentRow.GetCell(columnNum);  
  8.                     int length = Encoding.UTF8.GetBytes(currentCell.ToString()).Length;//获取当前单元格的内容宽度  
  9.                     if (columnWidth < length + 1)  
  10.                     {  
  11.                         columnWidth = length + 1;  
  12.                     }//若当前单元格内容宽度大于列宽,则调整列宽为当前单元格宽度,后面的+1是我人为的将宽度增加一个字符  
  13.                 }  
  14.                 ffSheet.SetColumnWidth(columnNum, columnWidth * 256);  
  15.             }</span>  

    columnNum是列号,从0开始循环到表格最后一列,循环的范围可以自己指定,原理很简单,就是在先循环列,在列上循环行,比对行内容宽度与列宽度,若行内容宽度大于列宽则增大列宽,循环以后,每列宽度等于该列中最宽的那一行的宽度。

     值得注意的是使用UTF8编码来计算的,在UTF8编码中数字和英文字母宽度为2,汉字宽度为3。而且字号越小,其效果就越好。在实际使用中内容为10磅的时候,其效果就相当不错。

      仅仅有宽度自适应是不够的,宽度自适应只是针对较短的内容而言的,如果单元格内容很长采用这个方法会将表格拉的非常宽。下面来谈一谈高度自适应解决方法, 高度自适应是指内容换行后行高能够自动增加以完整的显示内容,高度自适应是我自己想出来的,和宽度自适应很类似:

 

  1. <span style="font-family:Microsoft YaHei;font-size:14px;">    for (int rowNum = 2; rowNum <= ffSheet.LastRowNum; rowNum++)  
  2.             {  
  3.                 IRow currentRow = ffSheet.GetRow(rowNum);  
  4.                 ICell currentCell = currentRow.GetCell(27);  
  5.                 int length = Encoding.UTF8.GetBytes(currentCell.ToString()).Length;  
  6.                 currentRow.HeightInPoints = 20 * (length / 60 + 1);  
  7.             }</span>  

    首先要设置该列能够自动换行,然后将行高设置为20,获得列内容宽度后整除一个列宽常数,将其倍数乘以行高,从而增加行高。值得注意的是这个常数需要自己 测试,因为实际内容都是英文、数字和汉字混杂的,很难判断一行能容纳多少个字符,只能取一个中间值,如果取的太大可能会造成行高小于内容,取的过小会造成 行高过大而内容较少。而且在字磅数较小时精度较好。

posted on 2014-11-21 14:53  Knight_AWP  阅读(14886)  评论(0编辑  收藏  举报

导航