NPOI+ExcelReport に基づいたインポートおよびエクスポート EXCEL クラス ライブラリを共有します: ExcelUt
Jul 06, 2016 pm 01:30 PM自ExcelUtility類推出以來,經(jīng)過項(xiàng)目中的實(shí)際使用與不斷完善,現(xiàn)在又做了許多的優(yōu)化并增加了許多的功能,本篇不再講述原理,直接貼出示例代碼以及相關(guān)的模板、結(jié)果圖,以便大家快速掌握,另外這些示例說明我也已同步到GIT中,大家可以下載與學(xué)習(xí),不足之處,
自ExcelUtility類推出以來,經(jīng)過項(xiàng)目中的實(shí)際使用與不斷完善,現(xiàn)在又做了許多的優(yōu)化并增加了許多的功能,本篇不再講述原理,直接貼出示例代碼以及相關(guān)的模板、結(jié)果圖,以便大家快速掌握,另外這些示例說明我也已同步到GIT中,大家可以下載與學(xué)習(xí),不足之處,敬請見諒,謝謝!
一、ExcelUtility類庫操作說明(模板導(dǎo)出示例)
1.
/// <summary> /// 測試方法:測試依據(jù)模板+DataTable來生成EXCEL /// </summary> [TestMethod] public void TestExportToExcelWithTemplateByDataTable() { DataTable dt = GetDataTable();//獲取數(shù)據(jù) string templateFilePath = AppDomain.CurrentDomain.BaseDirectory + "/excel.xlsx"; //獲得EXCEL模板路徑 SheetFormatterContainer formatterContainers = new SheetFormatterContainer(); //實(shí)例化一個模板數(shù)據(jù)格式化容器 PartFormatterBuilder partFormatterBuilder = new PartFormatterBuilder();//實(shí)例化一個局部元素格式化器 partFormatterBuilder.AddFormatter("Title", "跨越IT學(xué)員");//將模板表格中Title的值設(shè)置為跨越IT學(xué)員 formatterContainers.AppendFormatterBuilder(partFormatterBuilder);//添加到工作薄格式容器中,注意只有添加進(jìn)去了才會生效 CellFormatterBuilder cellFormatterBuilder = new CellFormatterBuilder();//實(shí)例化一個單元格格式化器 cellFormatterBuilder.AddFormatter("rptdate", DateTime.Today.ToString("yyyy-MM-dd HH:mm"));//將模板表格中rptdate的值設(shè)置為當(dāng)前日期 formatterContainers.AppendFormatterBuilder(cellFormatterBuilder);//添加到工作薄格式容器中,注意只有添加進(jìn)去了才會生效 //實(shí)例化一個表格格式化器,dt.Select()是將DataTable轉(zhuǎn)換成DataRow[],name表示的模板表格中第一行第一個單元格要填充的數(shù)據(jù)參數(shù)名 TableFormatterBuilder<DataRow> tableFormatterBuilder = new TableFormatterBuilder<DataRow>(dt.Select(), "name"); tableFormatterBuilder.AddFormatters(new Dictionary<string, Func<DataRow, object>>{ {"name",r=>r["Col1"]},//將模板表格中name對應(yīng)DataTable中的列Col1 {"sex",r=>r["Col2"]},//將模板表格中sex對應(yīng)DataTable中的列Col2 {"km",r=>r["Col3"]},//將模板表格中km對應(yīng)DataTable中的列Col3 {"score",r=>r["Col4"]},//將模板表格中score對應(yīng)DataTable中的列Col4 {"result",r=>r["Col5"]}//將模板表格中result對應(yīng)DataTable中的列Co5 }); formatterContainers.AppendFormatterBuilder(tableFormatterBuilder);//添加到工作薄格式容器中,注意只有添加進(jìn)去了才會生效 string excelPath = ExcelUtility.Export.ToExcelWithTemplate(templateFilePath, "table", formatterContainers); Assert.IsTrue(File.Exists(excelPath)); }
模板如下:
導(dǎo)出結(jié)果如下:
2.
/// <summary> /// 測試方法:測試依據(jù)模板+List來生成EXCEL /// </summary> [TestMethod] public void TestExportToExcelWithTemplateByList() { List<Student> studentList = GetStudentList();//獲取數(shù)據(jù) string templateFilePath = AppDomain.CurrentDomain.BaseDirectory + "/excel.xlsx"; //獲得EXCEL模板路徑 SheetFormatterContainer formatterContainers = new SheetFormatterContainer(); //實(shí)例化一個模板數(shù)據(jù)格式化容器 PartFormatterBuilder partFormatterBuilder = new PartFormatterBuilder();//實(shí)例化一個局部元素格式化器 partFormatterBuilder.AddFormatter("Title", "跨越IT學(xué)員");//將模板表格中Title的值設(shè)置為跨越IT學(xué)員 formatterContainers.AppendFormatterBuilder(partFormatterBuilder);//添加到工作薄格式容器中,注意只有添加進(jìn)去了才會生效 CellFormatterBuilder cellFormatterBuilder = new CellFormatterBuilder();//實(shí)例化一個單元格格式化器 cellFormatterBuilder.AddFormatter("rptdate", DateTime.Today.ToString("yyyy-MM-dd HH:mm"));//將模板表格中rptdate的值設(shè)置為當(dāng)前日期 formatterContainers.AppendFormatterBuilder(cellFormatterBuilder);//添加到工作薄格式容器中,注意只有添加進(jìn)去了才會生效 //實(shí)例化一個表格格式化器,studentList本身就是可枚舉的無需轉(zhuǎn)換,name表示的模板表格中第一行第一個單元格要填充的數(shù)據(jù)參數(shù)名 TableFormatterBuilder<Student> tableFormatterBuilder = new TableFormatterBuilder<Student>(studentList, "name"); tableFormatterBuilder.AddFormatters(new Dictionary<string, Func<Student, object>>{ {"name",r=>r.Name},//將模板表格中name對應(yīng)Student對象中的屬性Name {"sex",r=>r.Sex},//將模板表格中sex對應(yīng)Student對象中的屬性Sex {"km",r=>r.KM},//將模板表格中km對應(yīng)Student對象中的屬性KM {"score",r=>r.Score},//將模板表格中score對應(yīng)Student對象中的屬性Score {"result",r=>r.Result}//將模板表格中result對應(yīng)Student對象中的屬性Result }); formatterContainers.AppendFormatterBuilder(tableFormatterBuilder); string excelPath = ExcelUtility.Export.ToExcelWithTemplate(templateFilePath, "table", formatterContainers); Assert.IsTrue(File.Exists(excelPath)); }
模板同上一個模板
導(dǎo)出結(jié)果如下:
3.
/// <summary> /// 測試方法:測試依據(jù)模板+DataTable來生成多表格EXCEL(注意:由于ExcelReport框架限制,目前僅支持模板文件格式為:xls) /// </summary> [TestMethod] public void TestExportToRepeaterExcelWithTemplateByDataTable() { DataTable dt = GetDataTable();//獲取數(shù)據(jù) string templateFilePath = AppDomain.CurrentDomain.BaseDirectory + "/excel2.xls"; //獲得EXCEL模板路徑 SheetFormatterContainer formatterContainers = new SheetFormatterContainer(); //實(shí)例化一個模板數(shù)據(jù)格式化容器 //實(shí)例化一個可重復(fù)表格格式化器,dt.Select()是將DataTable轉(zhuǎn)換成DataRow[],rpt_begin表示的模板表格開始位置參數(shù)名,rpt_end表示的模板表格結(jié)束位置參數(shù)名 RepeaterFormatterBuilder<DataRow> tableFormatterBuilder = new RepeaterFormatterBuilder<DataRow>(dt.Select(), "rpt_begin", "rpt_end"); tableFormatterBuilder.AddFormatters(new Dictionary<string, Func<DataRow, object>>{ {"sex",r=>r["Col2"]},//將模板表格中sex對應(yīng)DataTable中的列Col2 {"km",r=>r["Col3"]},//將模板表格中km對應(yīng)DataTable中的列Col3 {"score",r=>r["Col4"]},//將模板表格中score對應(yīng)DataTable中的列Col4 {"result",r=>r["Col5"]}//將模板表格中result對應(yīng)DataTable中的列Co5 }); PartFormatterBuilder<DataRow> partFormatterBuilder2 = new PartFormatterBuilder<DataRow>();//實(shí)例化一個可嵌套的局部元素格式化器 partFormatterBuilder2.AddFormatter("name", r => r["Col1"]);//將模板表格中name對應(yīng)DataTable中的列Col1 tableFormatterBuilder.AppendFormatterBuilder(partFormatterBuilder2);//添加到可重復(fù)表格格式化器中,作為其子格式化器 CellFormatterBuilder<DataRow> cellFormatterBuilder = new CellFormatterBuilder<DataRow>();//實(shí)例化一個可嵌套的單元格格式化器 cellFormatterBuilder.AddFormatter("rptdate", r => DateTime.Today.ToString("yyyy-MM-dd HH:mm"));//將模板表格中rptdate的值設(shè)置為當(dāng)前日期 tableFormatterBuilder.AppendFormatterBuilder(cellFormatterBuilder);//添加到可重復(fù)表格格式化器中,作為其子格式化器 formatterContainers.AppendFormatterBuilder(tableFormatterBuilder);//添加到工作薄格式容器中,注意只有添加進(jìn)去了才會生效 string excelPath = ExcelUtility.Export.ToExcelWithTemplate(templateFilePath, "multtable", formatterContainers); Assert.IsTrue(File.Exists(excelPath)); }
模板如下:
導(dǎo)出結(jié)果如下:
4.
/// <summary> /// 測試方法:測試依據(jù)復(fù)雜模板(含固定表格,可重復(fù)表格)+DataTable來生成EXCEL (注意:由于ExcelReport框架限制,目前僅支持模板文件格式為:xls) /// </summary> [TestMethod] public void TestExportToExcelWithTemplateByList2() { var schoolLevelList = SchoolLevel.GetList(); var classList = ClassInfo.GetList(); string templateFilePath = AppDomain.CurrentDomain.BaseDirectory + "/mb.xls"; //獲得EXCEL模板路徑 SheetFormatterContainer formatterContainers = new SheetFormatterContainer(); //實(shí)例化一個模板數(shù)據(jù)格式化容器 PartFormatterBuilder partFormatterBuilder = new PartFormatterBuilder(); partFormatterBuilder.AddFormatter("school", "跨越小學(xué)"); formatterContainers.AppendFormatterBuilder(partFormatterBuilder); TableFormatterBuilder<SchoolLevel> tableFormatterBuilder = new TableFormatterBuilder<SchoolLevel>(schoolLevelList, "lv");//實(shí)例化一個表格格式化器 tableFormatterBuilder.AddFormatters(new Dictionary<string, Func<SchoolLevel, object>> { {"lv",r=>r.LevelName}, //模板參數(shù)與數(shù)據(jù)源SchoolLevel屬性對應(yīng)關(guān)系,下同 {"clscount",r=>r.ClassCount}, {"lvmaster",r=>r.Master} }); formatterContainers.AppendFormatterBuilder(tableFormatterBuilder);//添加到工作薄格式容器中,注意只有添加進(jìn)去了才會生效 RepeaterFormatterBuilder<ClassInfo> repeaterFormatterBuilder = new RepeaterFormatterBuilder<ClassInfo>(classList, "lv_begin", "lv_end");//實(shí)例化一個可重復(fù)表格格式化器 repeaterFormatterBuilder.AddFormatters(new Dictionary<string, Func<ClassInfo, object>> { {"class",r=>r.ClassName}, //模板參數(shù)與數(shù)據(jù)源ClassInfo屬性對應(yīng)關(guān)系,下同 {"stucount",r=>r.StudentCount}, {"clsmaster",r=>r.Master}, {"lvitem",r=>r.LevelName} }); formatterContainers.AppendFormatterBuilder(repeaterFormatterBuilder);//添加到工作薄格式容器中,注意只有添加進(jìn)去了才會生效 string excelPath = ExcelUtility.Export.ToExcelWithTemplate(templateFilePath, "school", formatterContainers); Assert.IsTrue(File.Exists(excelPath)); }
模板如下:
導(dǎo)出結(jié)果如下:
5.
/// <summary> /// 測試方法:測試依據(jù)復(fù)雜模板(含固定表格,可重復(fù)表格中嵌套表格)+DataTable來生成EXCEL (注意:由于ExcelReport框架限制,目前僅支持模板文件格式為:xls) /// </summary> [TestMethod] public void TestExportToExcelWithTemplateByList3() { var schoolLevelList = SchoolLevel.GetList(); var classList = ClassInfo.GetListWithLevels(); string templateFilePath = AppDomain.CurrentDomain.BaseDirectory + "/mb1.xls"; //獲得EXCEL模板路徑 SheetFormatterContainer formatterContainers = new SheetFormatterContainer(); //實(shí)例化一個模板數(shù)據(jù)格式化容器 PartFormatterBuilder partFormatterBuilder = new PartFormatterBuilder(); partFormatterBuilder.AddFormatter("school", "跨越小學(xué)"); formatterContainers.AppendFormatterBuilder(partFormatterBuilder); TableFormatterBuilder<SchoolLevel> tableFormatterBuilder = new TableFormatterBuilder<SchoolLevel>(schoolLevelList, "lv");//實(shí)例化一個表格格式化器 tableFormatterBuilder.AddFormatters(new Dictionary<string, Func<SchoolLevel, object>> { {"lv",r=>r.LevelName}, //模板參數(shù)與數(shù)據(jù)源SchoolLevel屬性對應(yīng)關(guān)系,下同 {"clscount",r=>r.ClassCount}, {"lvmaster",r=>r.Master} }); formatterContainers.AppendFormatterBuilder(tableFormatterBuilder);//添加到工作薄格式容器中,注意只有添加進(jìn)去了才會生效 RepeaterFormatterBuilder<KeyValuePair<string, List<ClassInfo>>> repeaterFormatterBuilder = new RepeaterFormatterBuilder<KeyValuePair<string, List<ClassInfo>>>(classList, "lv_begin", "lv_end"); repeaterFormatterBuilder.AddFormatter("lvitem",r=>r.Key); TableFormatterBuilder<KeyValuePair<string, List<ClassInfo>>,ClassInfo> tableFormatterBuilder2=new TableFormatterBuilder<KeyValuePair<string, List<ClassInfo>>,ClassInfo>(r=>r.Value,"class"); tableFormatterBuilder2.AddFormatter("class",r=>r.ClassName); tableFormatterBuilder2.AddFormatter("stucount",r=>r.StudentCount); tableFormatterBuilder2.AddFormatter("clsmaster",r=>r.Master); repeaterFormatterBuilder.AppendFormatterBuilder(tableFormatterBuilder2); formatterContainers.AppendFormatterBuilder(repeaterFormatterBuilder);//添加到工作薄格式容器中,注意只有添加進(jìn)去了才會生效 string excelPath = ExcelUtility.Export.ToExcelWithTemplate(templateFilePath, "school", formatterContainers); Assert.IsTrue(File.Exists(excelPath)); }
模板如下:
導(dǎo)出結(jié)果如下:
6.
/// <summary> /// 測試方法:測試依據(jù)復(fù)雜模板(多工作薄,且含固定表格,可重復(fù)表格)+DataSet來生成EXCEL,只支持XLS /// </summary> [TestMethod] public void TestExportToExcelWithTemplateByDataSet() { var ds = GetDataSet(); string templateFilePath = AppDomain.CurrentDomain.BaseDirectory + "/mb2.xls"; //獲得EXCEL模板路徑 Dictionary<string, SheetFormatterContainer> formatterContainerDic = new Dictionary<string, SheetFormatterContainer>(); //實(shí)例化一個模板數(shù)據(jù)格式化容器數(shù)組,包含兩個SheetFormatterContainer用于格式化兩個工作薄 #region 創(chuàng)建第一個工作薄格式化容器,并設(shè)置相關(guān)參數(shù)對應(yīng)關(guān)系 SheetFormatterContainer formatterContainer1 = new SheetFormatterContainer(); PartFormatterBuilder partFormatterBuilder = new PartFormatterBuilder(); partFormatterBuilder.AddFormatter("school", "跨越小學(xué)"); formatterContainer1.AppendFormatterBuilder(partFormatterBuilder); TableFormatterBuilder<DataRow> tableFormatterBuilder = new TableFormatterBuilder<DataRow>(ds.Tables[0].Select(), "lv");//實(shí)例化一個表格格式化器 tableFormatterBuilder.AddFormatters(new Dictionary<string, Func<DataRow, object>> { {"lv",r=>r["Col1"]}, //模板參數(shù)與數(shù)據(jù)源DataTable屬性對應(yīng)關(guān)系,下同 {"clscount",r=>r["Col2"]}, {"lvmaster",r=>r["Col3"]} }); formatterContainer1.AppendFormatterBuilder(tableFormatterBuilder);//添加到工作薄格式容器中,注意只有添加進(jìn)去了才會生效 RepeaterFormatterBuilder<DataRow> repeaterFormatterBuilder = new RepeaterFormatterBuilder<DataRow>(ds.Tables[1].Select(), "lv_begin", "lv_end");//實(shí)例化一個可重復(fù)表格格式化器 repeaterFormatterBuilder.AddFormatters(new Dictionary<string, Func<DataRow, object>> { {"class",r=>r["Col1"]}, //模板參數(shù)與數(shù)據(jù)源ClassInfo屬性對應(yīng)關(guān)系,下同 {"stucount",r=>r["Col2"]}, {"clsmaster",r=>r["Col3"]}, {"lvitem",r=>r["Col4"]} }); formatterContainer1.AppendFormatterBuilder(repeaterFormatterBuilder);//添加到工作薄格式容器中,注意只有添加進(jìn)去了才會生效 formatterContainerDic.Add("table1", formatterContainer1);//添加到工作薄格式容器數(shù)組中,注意此處的Key值為模板上工作薄的名稱,此處即為:table1 #endregion #region 創(chuàng)建第二個工作薄格式化容器,并設(shè)置相關(guān)參數(shù)對應(yīng)關(guān)系 SheetFormatterContainer formatterContainer2 = new SheetFormatterContainer(); //實(shí)例化一個模板數(shù)據(jù)格式化容器 PartFormatterBuilder partFormatterBuilder2 = new PartFormatterBuilder();//實(shí)例化一個局部元素格式化器 partFormatterBuilder2.AddFormatter("Title", "跨越IT學(xué)員");//將模板表格中Title的值設(shè)置為跨越IT學(xué)員 formatterContainer2.AppendFormatterBuilder(partFormatterBuilder2);//添加到工作薄格式容器中,注意只有添加進(jìn)去了才會生效 CellFormatterBuilder cellFormatterBuilder2 = new CellFormatterBuilder();//實(shí)例化一個單元格格式化器 cellFormatterBuilder2.AddFormatter("rptdate", DateTime.Today.ToString("yyyy-MM-dd HH:mm"));//將模板表格中rptdate的值設(shè)置為當(dāng)前日期 formatterContainer2.AppendFormatterBuilder(cellFormatterBuilder2);//添加到工作薄格式容器中,注意只有添加進(jìn)去了才會生效 //實(shí)例化一個表格格式化器,dt.Select()是將DataTable轉(zhuǎn)換成DataRow[],name表示的模板表格中第一行第一個單元格要填充的數(shù)據(jù)參數(shù)名 TableFormatterBuilder<DataRow> tableFormatterBuilder2 = new TableFormatterBuilder<DataRow>(ds.Tables[2].Select(), "name"); tableFormatterBuilder2.AddFormatters(new Dictionary<string, Func<DataRow, object>>{ {"name",r=>r["Col1"]},//將模板表格中name對應(yīng)DataTable中的列Col1 {"sex",r=>r["Col2"]},//將模板表格中sex對應(yīng)DataTable中的列Col2 {"km",r=>r["Col3"]},//將模板表格中km對應(yīng)DataTable中的列Col3 {"score",r=>r["Col4"]},//將模板表格中score對應(yīng)DataTable中的列Col4 {"result",r=>r["Col5"]}//將模板表格中result對應(yīng)DataTable中的列Co5 }); formatterContainer2.AppendFormatterBuilder(tableFormatterBuilder2);//添加到工作薄格式容器中,注意只有添加進(jìn)去了才會生效 formatterContainerDic.Add("table2", formatterContainer2);//添加到工作薄格式容器數(shù)組中,注意此處的Key值為模板上工作薄的名稱,此處即為:table2 #endregion string excelPath = ExcelUtility.Export.ToExcelWithTemplate(templateFilePath, formatterContainerDic); Assert.IsTrue(File.Exists(excelPath)); }
模板如下:
導(dǎo)出結(jié)果如下:
二、ExcelUtility類庫操作說明(嵌入圖片示例)
一、 制作模板(含圖片)
1. 制作模板的文件格式需為兼容格式,即:xls或xlt;
2. 模板變量(或稱為占位符)定義與之前相同,即:$[變量名];
3. 圖片變量定義如下:
a) 繪制一個圖形,圖形形狀盡可能的與要顯示的圖片相同,比如:印章,則可繪制一個圓形;
b) 圖形必需是透明背景,邊框可要可不要,建議留著,這樣后續(xù)調(diào)整比較方便,如下圖中的藍(lán)色透明背景圓形:
c) 圖形大小盡可能與要顯示的圖片大小相同,如下圖示:
由于EXCEL上大小默認(rèn)采用厘米,而圖片一般采用像素,所以需要自己換算一下像素對應(yīng)的厘米數(shù)(也可將EXCEL計(jì)算單位設(shè)為像素,方法自行網(wǎng)上查找);也可網(wǎng)上下載單位轉(zhuǎn)換工具
另外圖形屬性建議設(shè)置成如下圖:
溫馨提示:圖形形狀、屬性若未設(shè)置一般不影響導(dǎo)出效果,但不排除其它異常情況,圖形大小是一定要設(shè)置,且盡可能與要顯示圖形大小(高、寬)相同,否則有可能造成導(dǎo)出變形
代碼示例:
/// <summary> /// 測試方法:測試依據(jù)模板+DataTable+圖片來生成包含圖片的EXCEL,只支持XLS /// </summary> [TestMethod] public void TestInsertPic() { DataTable dt = GetDataTable();//獲取數(shù)據(jù) string templateFilePath = AppDomain.CurrentDomain.BaseDirectory + "/excel.xls"; //獲得EXCEL模板路徑 SheetFormatterContainer formatterContainers = new SheetFormatterContainer(); //實(shí)例化一個模板數(shù)據(jù)格式化容器 PartFormatterBuilder partFormatterBuilder = new PartFormatterBuilder();//實(shí)例化一個局部元素格式化器 partFormatterBuilder.AddFormatter("Title", "跨越IT學(xué)員");//將模板表格中Title的值設(shè)置為跨越IT學(xué)員d formatterContainers.AppendFormatterBuilder(partFormatterBuilder);//添加到工作薄格式容器中,注意只有添加進(jìn)去了才會生效 CellFormatterBuilder cellFormatterBuilder = new CellFormatterBuilder();//實(shí)例化一個單元格格式化器 cellFormatterBuilder.AddFormatter("rptdate", DateTime.Today.ToString("yyyy-MM-dd HH:mm"));//將模板表格中rptdate的值設(shè)置為當(dāng)前日期 formatterContainers.AppendFormatterBuilder(cellFormatterBuilder);//添加到工作薄格式容器中,注意只有添加進(jìn)去了才會生效 //實(shí)例化一個表格格式化器,dt.Select()是將DataTable轉(zhuǎn)換成DataRow[],name表示的模板表格中第一行第一個單元格要填充的數(shù)據(jù)參數(shù)名 TableFormatterBuilder<DataRow> tableFormatterBuilder = new TableFormatterBuilder<DataRow>(dt.Select(), "name"); tableFormatterBuilder.AddFormatters(new Dictionary<string, Func<DataRow, object>>{ {"name",r=>r["Col1"]},//將模板表格中name對應(yīng)DataTable中的列Col1 {"sex",r=>r["Col2"]},//將模板表格中sex對應(yīng)DataTable中的列Col2 {"km",r=>r["Col3"]},//將模板表格中km對應(yīng)DataTable中的列Col3 {"score",r=>r["Col4"]},//將模板表格中score對應(yīng)DataTable中的列Col4 {"result",r=>r["Col5"]}//將模板表格中result對應(yīng)DataTable中的列Co5 }); formatterContainers.AppendFormatterBuilder(tableFormatterBuilder);//添加到工作薄格式容器中,注意只有添加進(jìn)去了才會生效 string picPath = AppDomain.CurrentDomain.BaseDirectory + "\\tz.png";//圖片路徑 PictureWithShapeFormatterBuilder pictureBuilder = new PictureWithShapeFormatterBuilder();//實(shí)例化一個圖片關(guān)聯(lián)圖形格式化器 //pictureBuilder.AddFormatter(picPath);//當(dāng)sheet中只有一個圖形時,我們可以省略指定區(qū)域,那么默認(rèn)就是把整個工作薄區(qū)域當(dāng)成一個尋找圖形區(qū)域,若sheet中包含多個,則應(yīng)指定區(qū)域,替換成如下語句 pictureBuilder.AddFormatter(picPath,5,60000, 0, 3, false);//第一個參數(shù)為圖片路徑,中間4個參數(shù)為數(shù)字型指定圖形尋找的工作薄區(qū)域(行索引,列索引,索引從0開始計(jì)),最后一個為是否自適應(yīng)大小,一般不建議使用,除非壓縮圖片 formatterContainers.AppendFormatterBuilder(pictureBuilder); string excelPath = ExcelUtility.Export.ToExcelWithTemplate(templateFilePath, "table", formatterContainers); Assert.IsTrue(File.Exists(excelPath)); }
模板如下:
注意圖片若需要為透明背景格式,則必需使用PNG格式,NPOI支持的圖片主要格式有:PNG,JPG
導(dǎo)出結(jié)果如下:
溫馨提示:
pictureBuilder.AddFormatter(picPath);//當(dāng)sheet中只有一個圖形時,我們可以省略指定區(qū)域,那么默認(rèn)就是把整個工作薄區(qū)域當(dāng)成一個尋找圖形區(qū)域,若sheet中包含多個,則應(yīng)指定區(qū)域,替換成如下語句
pictureBuilder.AddFormatter(picPath,5,60000, 0, 3, false);//第一個參數(shù)為圖片路徑,中間4個參數(shù)為數(shù)字型指定圖形尋找的工作薄區(qū)域(行索引(起止),列索引(起止),索引從0開始計(jì)),最后一個為是否自適應(yīng)大小,一般不建議使用,除非壓縮圖片
如果圖形可能隨單元格進(jìn)行位置調(diào)整,那么在指定圖形區(qū)域時需注意,如果圖形會隨單元格下移,那么結(jié)束行索引(MinRow)就需要指定一個可能的最大值或不指定,如果圖形會隨單元格右移,那么結(jié)束列索引(MinColumn)就需要指定一個可能的最大值或不指定,如果存在多個圖形區(qū)域,則上述情況都必需給定具體值(可能的最大值),以免造成區(qū)域交叉,從而導(dǎo)致圖片顯示不正確,如下示例:
//圖形可能下移,可能右移,那么將結(jié)束行設(shè)為可能最大值:60000,結(jié)束列設(shè)為可能最大值:255
pictureBuilder.AddFormatter(picPath, 5, 60000, 0, 255, false);
//此處只指定開始行與開始列,與上面差不多,但建議使用上面的用法
pictureBuilder.AddFormatter(new PictureWithShapeInfo(picPath, new SheetRange() {MinRow=5,MinColumn=0 },false));
特別說明:
1.本類庫是基于NPOI+ExcelReport,所有功能凡我的類庫能夠?qū)崿F(xiàn)的,NPOI與ExcelReport都可以實(shí)現(xiàn),只是用法及復(fù)雜程度不同而矣,我封裝的目的就是為了降低大家的學(xué)習(xí)難度,提高使用效率,免費(fèi)且開源,源代碼同步更新至開源社區(qū)的GIT目錄中,具體地址請看我該系列之前的文章有列出,在此就不再說明。
2.上述圖片關(guān)聯(lián)圖形顯示功能我是在ExcelReport基礎(chǔ)上增加了一個PictureWithShapeFormatter類及其相關(guān)的類:PictureWithShapeInfo、SheetRange,因沒有關(guān)聯(lián)GIT,所以是在本地更新的,這幾個類的代碼如下:
PictureWithShapeFormatter:
using NPOI.Extend; using NPOI.HSSF.UserModel; using NPOI.SS.UserModel; using NPOI.XSSF.UserModel; using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ExcelReport { public class PictureWithShapeFormatter : ElementFormatter { PRivate PictureWithShapeInfo PictureInfo = null; public PictureWithShapeFormatter(PictureWithShapeInfo pictureInfo) { this.PictureInfo = pictureInfo; } public override void Format(SheetAdapter sheetAdapter) { var sheet = sheetAdapter.CurrentSheet; var shapes = PictureInfo.GetShapes(sheet); bool isCompatible = false; if (sheet is HSSFSheet) { isCompatible = true; } if (shapes == null || shapes.Count <= 0) { throw new Exception(string.Format("未能獲取到工作薄[{0}]指定區(qū)域的圖形對象列表!", sheet.SheetName)); } byte[] bytes = System.IO.File.ReadAllBytes(PictureInfo.FilePath); int pictureIdx = -1; IDrawing drawing = null; IClientAnchor anchor = null; if (isCompatible) { var shape = shapes[0] as HSSFShape; anchor = shape.Anchor as IClientAnchor; drawing = shape.Patriarch; shape.LineStyle = LineStyle.None; } else { var shape = shapes[0] as XSSFShape; anchor = shape.GetAnchor() as IClientAnchor; drawing = shape.GetDrawing(); shape.LineStyle = LineStyle.None; } pictureIdx = sheet.Workbook.AddPicture(bytes, PictureInfo.PictureType); var picture = drawing.CreatePicture(anchor, pictureIdx); if (PictureInfo.AutoSize) { picture.Resize(); } } } }
PictureWithShapeInfo、SheetRange:
using NPOI.SS.UserModel; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; using NPOI.HSSF.UserModel; using NPOI.XSSF.UserModel; using NPOI.Extend; namespace ExcelReport { /// <summary> /// 圖片關(guān)聯(lián)圖形信息 /// 作者:Zuowenjun /// </summary> public class PictureWithShapeInfo { private SheetRange _SheetRange = new SheetRange(); public string FilePath { get; set; } public PictureType PictureType { get; set; } public SheetRange ShapeRange { get { return _SheetRange; } set { if (value != null) { _SheetRange = value; } } } public bool AutoSize { get; set; } public PictureWithShapeInfo() { } public PictureWithShapeInfo(string filePath, SheetRange shapeRange = null, bool autoSize = false) { this.FilePath = filePath; this.ShapeRange = shapeRange; this.AutoSize = autoSize; this.PictureType = GetPictureType(filePath); } public List<object> GetShapes(ISheet sheet) { List<object> shapeAllList = new List<object>(); var shapeContainer = sheet.DrawingPatriarch; if (sheet is HSSFSheet) { var shapeContainerHSSF = sheet.DrawingPatriarch as HSSFShapeContainer; if (null != shapeContainer) { var shapeList = shapeContainerHSSF.Children; foreach (var shape in shapeList) { if (shape is HSSFShape && shape.Anchor is HSSFClientAnchor) { var anchor = shape.Anchor as HSSFClientAnchor; if (IsInternalOrIntersect(ShapeRange.MinRow, ShapeRange.MaxRow, ShapeRange.MinColumn, ShapeRange.MaxColumn, anchor.Row1, anchor.Row2, anchor.Col1, anchor.Col2, true)) { shapeAllList.Add(shape); } } } } } else { var documentPartList = (sheet as XSSFSheet).GetRelations(); foreach (var documentPart in documentPartList) { if (documentPart is XSSFDrawing) { var drawing = (XSSFDrawing)documentPart; var shapeList = drawing.GetShapes(); foreach (var shape in shapeList) { var anchorResult = shape.GetAnchor(); if (shape is XSSFShape && anchorResult is XSSFClientAnchor) { var anchor = anchorResult as XSSFClientAnchor; if (IsInternalOrIntersect(ShapeRange.MinRow, ShapeRange.MaxRow, ShapeRange.MinColumn, ShapeRange.MaxColumn, anchor.Row1, anchor.Row2, anchor.Col1, anchor.Col2, true)) { shapeAllList.Add(shape); } } } } } } return shapeAllList; } private PictureType GetPictureType(string filePath) { string ext = Path.GetExtension(filePath).ToUpper(); switch (ext) { case ".JPG": { return PictureType.JPEG; } case ".PNG": { return PictureType.PNG; } default: { return PictureType.None; } } } private bool IsInternalOrIntersect(int? rangeMinRow, int? rangeMaxRow, int? rangeMinCol, int? rangeMaxCol, int pictureMinRow, int pictureMaxRow, int pictureMinCol, int pictureMaxCol, bool onlyInternal) { int _rangeMinRow = rangeMinRow ?? pictureMinRow; int _rangeMaxRow = rangeMaxRow ?? pictureMaxRow; int _rangeMinCol = rangeMinCol ?? pictureMinCol; int _rangeMaxCol = rangeMaxCol ?? pictureMaxCol; if (onlyInternal) { return (_rangeMinRow <= pictureMinRow && _rangeMaxRow >= pictureMaxRow && _rangeMinCol <= pictureMinCol && _rangeMaxCol >= pictureMaxCol); } else { return ((Math.Abs(_rangeMaxRow - _rangeMinRow) + Math.Abs(pictureMaxRow - pictureMinRow) >= Math.Abs(_rangeMaxRow + _rangeMinRow - pictureMaxRow - pictureMinRow)) && (Math.Abs(_rangeMaxCol - _rangeMinCol) + Math.Abs(pictureMaxCol - pictureMinCol) >= Math.Abs(_rangeMaxCol + _rangeMinCol - pictureMaxCol - pictureMinCol))); } } } /// <summary> /// 工作薄區(qū)域 /// 作者:Zuowenjun /// </summary> public class SheetRange { public int? MinRow { get; set; } public int? MaxRow { get; set; } public int? MinColumn { get; set; } public int? MaxColumn { get; set; } public SheetRange() { } public SheetRange(int minRow, int maxRow, int minColumn, int maxColumn) { this.MinRow = minRow; this.MaxRow = maxRow; this.MinColumn = minColumn; this.MaxColumn = maxColumn; } public override bool Equals(object obj) { bool equalResult = false; equalResult = base.Equals(obj); if (!equalResult) { var otherSheetRange = obj as SheetRange; if (otherSheetRange != null) { equalResult = (this.MinRow <= otherSheetRange.MinRow && this.MaxRow >= otherSheetRange.MaxRow && this.MinColumn <= otherSheetRange.MinColumn && this.MaxColumn >= otherSheetRange.MaxColumn); } } return equalResult; } public override int GetHashCode() { return this.ToString().GetHashCode(); } public override string ToString() { return string.Format("MinRow:{0},MaxRow:{1},MinColumn:{2},MaxColumn:{3}", this.MinRow, this.MaxRow, this.MinColumn, this.MaxColumn); } } }
分享我基于NPOI+ExcelReport實(shí)現(xiàn)的導(dǎo)入與導(dǎo)出EXCEL類庫:ExcelUtility 其它相關(guān)文章鏈接:
分享我基于NPOI+ExcelReport實(shí)現(xiàn)的導(dǎo)入與導(dǎo)出EXCEL類庫:ExcelUtility?
分享我基于NPOI+ExcelReport實(shí)現(xiàn)的導(dǎo)入與導(dǎo)出EXCEL類庫:ExcelUtility (續(xù)篇)?

ホットAIツール

Undress AI Tool
脫衣畫像を無料で

Undresser.AI Undress
リアルなヌード寫真を作成する AI 搭載アプリ

AI Clothes Remover
寫真から衣服を削除するオンライン AI ツール。

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中國語版
中國語版、とても使いやすい

ゼンドスタジオ 13.0.1
強(qiáng)力な PHP 統(tǒng)合開発環(huán)境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

Quark Netdisk と Baidu Netdisk は非常に便利なストレージ ツールですが、多くのユーザーはこれら 2 つのソフトウェアが相互運(yùn)用可能かどうかを疑問に思っています。 Quark NetdiskをBaidu Netdiskに共有するにはどうすればよいですか?このサイトでは、QuarkネットワークディスクファイルをBaiduネットワークディスクに保存する方法をユーザーに詳しく紹介します。 Quark Network Disk から Baidu Network Disk にファイルを保存する方法 方法 1. Quark Network Disk から Baidu Network Disk にファイルを転送する方法を知りたい場合は、まず Quark Network Disk に保存する必要があるファイルをダウンロードして、次に開きますBaidu Network Disk クライアントを起動し、圧縮ファイルを保存するフォルダーを選択し、ダブルクリックしてフォルダーを開きます。 2. フォルダーを開いたら、ウィンドウ左上の「アップロード」をクリックします。 3. コンピュータ上でアップロードする必要がある圧縮ファイルを見つけ、クリックして選択します。

Huawei 攜帯電話にデュアル WeChat ログインを?qū)g裝するにはどうすればよいですか?ソーシャルメディアの臺頭により、WeChatは人々の日常生活に欠かせないコミュニケーションツールの1つになりました。ただし、多くの人は、同じ攜帯電話で同時に複數(shù)の WeChat アカウントにログインするという問題に遭遇する可能性があります。 Huawei 社の攜帯電話ユーザーにとって、WeChat の二重ログインを?qū)g現(xiàn)することは難しくありませんが、この記事では Huawei 社の攜帯電話で WeChat の二重ログインを?qū)g現(xiàn)する方法を紹介します。まず第一に、ファーウェイの攜帯電話に付屬するEMUIシステムは、デュアルアプリケーションを開くという非常に便利な機(jī)能を提供します。アプリケーションのデュアルオープン機(jī)能により、ユーザーは同時に

このプラットフォームを使用して曲を聴く場合、ほとんどの曲には聴きたい曲がいくつかあるはずです。もちろん、著作権がないため聴けないものもあります。もちろん、一部の曲を直接使用することもできますローカルにインポートされています。そこに行って聞いてください。一部の曲をダウンロードして、mp3 形式に直接変換できるため、攜帯電話でスキャンしてインポートしたり、その他の狀況に使用したりできます。しかし、ほとんどのユーザーにとって、ローカルの曲コンテンツのインポートについてはよくわからないため、これらの問題をうまく解決するために、今日は編集者も説明します。興味がありますか、

1. まず、NetEase Cloud Music に入り、ソフトウェアのホームページ インターフェイスをクリックして、曲の再生インターフェイスに入ります。 2. 次に、曲の再生インターフェイスで、下の図の赤いボックスに示すように、右上隅にある共有機(jī)能ボタンを見つけて、クリックして共有チャンネルを選択し、共有チャンネルで「共有先」オプションをクリックします。下部にある [WeChat Moments] を選択すると、コンテンツを WeChat Moments に共有できます。

プログラミング言語 PHP は、さまざまなプログラミング ロジックやアルゴリズムをサポートできる、Web 開発用の強(qiáng)力なツールです。その中でも、フィボナッチ數(shù)列の実裝は、一般的で古典的なプログラミングの問題です。この記事では、PHP プログラミング言語を使用してフィボナッチ數(shù)列を?qū)g裝する方法を、具體的なコード例を添付して紹介します。フィボナッチ數(shù)列は、次のように定義される數(shù)學(xué)的數(shù)列です。數(shù)列の最初と 2 番目の要素は 1 で、3 番目の要素以降、各要素の値は前の 2 つの要素の合計(jì)に等しくなります。シーケンスの最初のいくつかの要素

タイトル: 中國語データを Oracle にインポートする際の文字化けの問題を解決する方法とコード例。中國語データを Oracle データベースにインポートすると、文字化けが頻繁に発生します。これは、データベースの文字セット設(shè)定が間違っているか、インポート中のエンコード変換の問題が原因である可能性があります。プロセス。 。この問題を解決するには、インポートされた中國語データが正しく表示されるようにするためのいくつかの方法を講じることができます。以下に、いくつかの解決策と具體的なコード例を示します。 1. データベースの文字セット設(shè)定を確認(rèn)します。 Oracle データベースでは、文字セット設(shè)定は次のとおりです。

最近、Baidu Netdisk Android クライアントの新しいバージョン 8.0.0 がリリースされ、このバージョンには多くの変更が加えられただけでなく、多くの実用的な機(jī)能も追加されました。その中でも最も目を引くのがフォルダー共有機(jī)能の強(qiáng)化だ。ユーザーは簡単に友人を招待して仕事や生活で重要なファイルを共有できるようになり、より便利なコラボレーションと共有が実現(xiàn)します。では、友達(dá)と共有する必要があるファイルをどのように共有すればよいでしょうか? 以下では、このサイトの編集者が詳しく説明します。 1) Baidu Cloud APP を開き、まずホームページ上の関連フォルダーをクリックして選択し、次にインターフェイスの右上隅にある [...] アイコンをクリックします (以下を參照) 2) 次に、[+] をクリックします。 「共有メンバー」欄】を選択し、最後に全てにチェックを入れます

PHP ゲーム要件実裝ガイド インターネットの普及と発展に伴い、Web ゲーム市場の人気はますます高まっています。多くの開発者は、PHP 言語を使用して獨(dú)自の Web ゲームを開発することを望んでおり、ゲーム要件の実裝は重要なステップです。この記事では、PHP 言語を使用して一般的なゲーム要件を?qū)g裝する方法を紹介し、具體的なコード例を示します。 1. ゲームキャラクターの作成 Web ゲームにおいて、ゲームキャラクターは非常に重要な要素です。ゲームキャラクターの名前、レベル、経験値などの屬性を定義し、これらを操作するメソッドを提供する必要があります。
