1. 程式人生 > >npoi自適應行高和列寬

npoi自適應行高和列寬

 由於系統需要在網頁上導 出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,獲得列內容寬度後整除一個列寬常數,將其倍數乘以行高,從而增加行高。值得注意的是這個常數需要自己 測試,因為實際內容都是英文、數字和漢字混雜的,很難判斷一行能容納多少個字元,只能取一箇中間值,如果取的太大可能會造成行高小於內容,取的過小會造成 行高過大而內容較少。而且在字磅數較小時精度較好。