如何在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有一個寬度自適應屬性,可惜只對英文和數字有效,對漢字無效。後來在一個臺灣博客上發現了一段解決代碼,我稍加改造後如下:

<span style="font-family:Microsoft YaHei;font-size:14px;">    for (int columnNum = 0; columnNum <= 26; columnNum++)
            {
                int columnWidth = ffSheet.GetColumnWidth(columnNum) / 256;//獲取當前列寬度
                for (int rowNum = 1; rowNum <= ffSheet.LastRowNum; rowNum++)//在這一列上循環行
                {
                    IRow currentRow = ffSheet.GetRow(rowNum);
                    ICell currentCell = currentRow.GetCell(columnNum);
                    int length = Encoding.UTF8.GetBytes(currentCell.ToString()).Length;//獲取當前單元格的內容寬度
                    if (columnWidth < length + 1)
                    {
                        columnWidth = length + 1;
                    }//若當前單元格內容寬度大於列寬,則調整列寬爲當前單元格寬度,後面的+1是我人爲的將寬度增加一個字符
                }
                ffSheet.SetColumnWidth(columnNum, columnWidth * 256);
            }</span>

    columnNum是列號,從0開始循環到表格最後一列,循環的範圍可以自己指定,原理很簡單,就是在先循環列,在列上循環行,比對行內容寬度與列寬度,若行內容寬度大於列寬則增大列寬,循環以後,每列寬度等於該列中最寬的那一行的寬度。

     值得注意的是使用UTF8編碼來計算的,在UTF8編碼中數字和英文字母寬度爲2,漢字寬度爲3。而且字號越小,其效果就越好。在實際使用中內容爲10磅的時候,其效果就相當不錯。

      僅僅有寬度自適應是不夠的,寬度自適應只是針對較短的內容而言的,如果單元格內容很長採用這個方法會將表格拉的非常寬。下面來談一談高度自適應解決方法,高度自適應是指內容換行後行高能夠自動增加以完整的顯示內容,高度自適應是我自己想出來的,和寬度自適應很類似:

 

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

    首先要設置該列能夠自動換行,然後將行高設置爲20,獲得列內容寬度後整除一個列寬常數,將其倍數乘以行高,從而增加行高。值得注意的是這個常數需要自己測試,因爲實際內容都是英文、數字和漢字混雜的,很難判斷一行能容納多少個字符,只能取一箇中間值,如果取的太大可能會造成行高小於內容,取的過小會造成行高過大而內容較少。而且在字磅數較小時精度較好。

    呵呵,老趙可以參考參考。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章