转自链接
2.3.5 IF函数
2.3.6 CountIf和SumIf函数
2.3.7 Lookup函数
2.3.8随机数函数
2.3.9通过NPOI获得公式的返回值
2.4创建图形
2.4.1画线
2.4.2画矩形
2.4.3画圆形
2.4.4画Grid
2.4.5插入图片
2.5打印相关设置
2.6
高级功能
2.6.1调整表单显示比例
2.6.2设置密码
2.6.3组合行、列
2.6.4锁定列
2.6.5显示/隐藏网格线
2.6.6设置初始视图的行、列
2.6.7数据有效性
2.6.8生成下拉式菜单
2.3.5用NPOI操作EXCEL--If函数
在Excel中,IF(logical_test,value_if_true,value_if_false)用来用作逻辑判断。其中Logical_test表示计算结果为TRUE或FALSE的任意值或表达式; value_if_true表示当表达式Logical_test的值为TRUE时的返回值;value_if_false表示当表达式Logical_test的值为FALSE时的返回值。同样在NPOI中也可以利用这个表达式进行各种逻辑运算。如下代码分别设置了B2和D2单元格的用于逻辑判断的公式。
HSSFSheet sheet1 = hssfworkbook.CreateSheet("Sheet1");
HSSFRow row1 = sheet1.CreateRow(
0);
row1.CreateCell(
0).SetCellValue("姓名");
row1.CreateCell(
1).SetCellValue("身份证号");
row1.CreateCell(
2).SetCellValue("性别");
row1.CreateCell(
3).SetCellValue("语文");
row1.CreateCell(
4).SetCellValue("是否合格");
HSSFRow row2 = sheet1.CreateRow(
1);
row2.CreateCell(
0).SetCellValue("令狐冲");
row2.CreateCell(
1).SetCellValue("420821198808101014");
row2.CreateCell(
2).SetCellFormula("IF(MOD(MID(B2,18,1),2)=0,\"男\",\"女\")");
row2.CreateCell(
3).SetCellValue(85);
row2.CreateCell(
4).SetCellFormula("IF(D2>60,IF(D2>90,\"优秀\",\"合格\"),\"不合格\")");
其中最关键的两句执行结果如下:
row2.CreateCell(2).SetCellFormula("IF(MOD(MID(B2,18,1),2)=0,\"男\",\"女\")");
row2.CreateCell(4).SetCellFormula("IF(D2>60,IF(D2>90,\"优秀\",\"合格\"),\"不合格\")");
下面分别对这几个函数作一些说明:
MOD(MID(B2,18,1),2)
:我们知道18位身份证号的第18位表示性别,偶数为男性,奇数为女性,所以用了MID(B2,18,1)取第18位数字(与C#中一般从0计数不同,第二个参数是从1算起,有关MID函数的更多信息,请参见字符串函数),用MOD取余函数判断奇偶。在Excel中对数据类型的控制没有C#中那么严格,如此例中我截取出来的是字符串,但当我做取余运算时Excel会自动转换。
IF(D2>60,IF(D2>90,"
优秀","合格"),"不合格"):这是IF的嵌套使用,表示90分以上为优秀,60分以上为合格,否则为不合格。
2.3.6用NPOI操作EXCEL--COUNTIF和SUMIF函数
一、COUNTIF这一节,我们一起来学习Excel中另一个常用的函数--COUNTIF函数,看函数名就知道这是一个用来在做满足某条件的计数的函数。先来看一看它的语法:COUNTIF(range,criteria),参数说明如下:
Range需要进行读数的计数
Criteria条件表达式,只有当满足此条件时才进行计数
接下来看一个例子,代码如下:
HSSFSheet sheet1 = hssfworkbook.CreateSheet("Sheet1");
HSSFRow row1 = sheet1.CreateRow(
0);
row1.CreateCell(
0).SetCellValue("姓名");
row1.CreateCell(
1).SetCellValue("成绩");
HSSFRow row2 = sheet1.CreateRow(
1);
row2.CreateCell(
0).SetCellValue("令狐冲");
row2.CreateCell(
1).SetCellValue(85);
HSSFRow row3 = sheet1.CreateRow(
2);
row3.CreateCell(
0).SetCellValue("任盈盈");
row3.CreateCell(
1).SetCellValue(90);
HSSFRow row4 = sheet1.CreateRow(
3);
row4.CreateCell(
0).SetCellValue("任我行");
row4.CreateCell(
1).SetCellValue(70);
HSSFRow row5 = sheet1.CreateRow(
4);
row5.CreateCell(
0).SetCellValue("左冷婵");
row5.CreateCell(
1).SetCellValue(45);
HSSFRow row6 = sheet1.CreateRow(
5);
row6.CreateCell(
0).SetCellValue("岳不群");
row6.CreateCell(
1).SetCellValue(50);
HSSFRow row7 = sheet1.CreateRow(
6);
row7.CreateCell(
0).SetCellValue("合格人数:");
row7.CreateCell(
1).SetCellFormula("COUNTIF(B2:B6,\">60\")");
执行结果如下:
我们可以看到,CountIf函数成功的统计出了区域“B2:B6”中成绩合格的人数(这里定义成绩大于60为合格)。
二、SUMIF
接下来,顺便谈谈另一个与CountIF类似的函数—SumIf函数。此函数用于统计某区域内满足某条件的值的求和(CountIf是计数)。与CountIF不同,SumIF有三个参数,语法为SumIF(criteria_range, criteria,sum_range),各参数的说明如下:
criteria_range条件测试区域,第二个参数Criteria中的条件将与此区域中的值进行比较
criteria条件测试值,满足条件的对应的sum_range项将进行求和计算
sum_range汇总数据所在区域,求和时会排除掉不满足Criteria条件的对应的项
我们还是以例子来加以说明:
Code
HSSFSheet sheet1 = hssfworkbook.CreateSheet(
"Sheet1");
HSSFRow row1 = sheet1.CreateRow(
0);
row1.CreateCell(
0).SetCellValue("姓名");
row1.CreateCell(
1).SetCellValue("月份");
row1.CreateCell(
2).SetCellValue("销售额");
HSSFRow row2 = sheet1.CreateRow(
1);
row2.CreateCell(
0).SetCellValue("令狐冲");
row2.CreateCell(
1).SetCellValue("一月");
row2.CreateCell(
2).SetCellValue(1000);
HSSFRow row3 = sheet1.CreateRow(
2);
row3.CreateCell(
0).SetCellValue("任盈盈");
row3.CreateCell(
1).SetCellValue("一月");
row3.CreateCell(
2).SetCellValue(900);
HSSFRow row4 = sheet1.CreateRow(
3);
row4.CreateCell(
0).SetCellValue("令狐冲");
row4.CreateCell(
1).SetCellValue("二月");
row4.CreateCell(
2).SetCellValue(2000);
HSSFRow row5 = sheet1.CreateRow(
4);
row5.CreateCell(
0).SetCellValue("任盈盈");
row5.CreateCell(
1).SetCellValue("二月");
row5.CreateCell(
2).SetCellValue(1000);
HSSFRow row6 = sheet1.CreateRow(
5);
row6.CreateCell(
0).SetCellValue("令狐冲");
row6.CreateCell(
1).SetCellValue("三月");
row6.CreateCell(
2).SetCellValue(3000);
HSSFRow row7 = sheet1.CreateRow(
6);
row7.CreateCell(
0).SetCellValue("任盈盈");
row7.CreateCell(
1).SetCellValue("三月");
row7.CreateCell(
2).SetCellValue(1200);
HSSFRow row8 = sheet1.CreateRow(
7);
row8.CreateCell(
0).SetCellValue("令狐冲一季度销售额:");
row8.CreateCell(
2).SetCellFormula("SUMIF(A2:A7,\"=令狐冲\",C2:C7)");
HSSFRow row9 = sheet1.CreateRow(
8);
row9.CreateCell(
0).SetCellValue("任盈盈一季度销售额:");
row9.CreateCell(
2).SetCellFormula("SUMIF(A2:A7,\"=任盈盈\",C2:C7)");
执行结果如下:
如上图,SUMIF统计出了不同人一季度的销售额。
2.3.7用NPOI操作EXCEL--LOOKUP函数
今天,我们一起学习Excel中的查询函数--LOOKUP。其基本语法形式为LOOKUP(lookup_value,lookup_vector,result_vector)。还是以例子加以说明更容易理解:
Code
HSSFSheet sheet1 = hssfworkbook.CreateSheet(
"Sheet1");
HSSFRow row1 = sheet1.CreateRow(
0);
row1.CreateCell(
0).SetCellValue("收入最低");
row1.CreateCell(
1).SetCellValue("收入最高");
row1.CreateCell(
2).SetCellValue("税率");
HSSFRow row2 = sheet1.CreateRow(
1);
row2.CreateCell(
0).SetCellValue(0);
row2.CreateCell(
1).SetCellValue(3000);
row2.CreateCell(
2).SetCellValue(0.1);
HSSFRow row3 = sheet1.CreateRow(
2);
row3.CreateCell(
0).SetCellValue(3001);
row3.CreateCell(
1).SetCellValue(10000);
row3.CreateCell(
2).SetCellValue(0.2);
HSSFRow row4 = sheet1.CreateRow(
3);
row4.CreateCell(
0).SetCellValue(10001);
row4.CreateCell(
1).SetCellValue(20000);
row4.CreateCell(
2).SetCellValue(0.3);
HSSFRow row5 = sheet1.CreateRow(
4);
row5.CreateCell(
0).SetCellValue(20001);
row5.CreateCell(
1).SetCellValue(50000);
row5.CreateCell(
2).SetCellValue(0.4);
HSSFRow row6 = sheet1.CreateRow(
5);
row6.CreateCell(
0).SetCellValue(50001);
row6.CreateCell(
2).SetCellValue(0.5);
HSSFRow row8 = sheet1.CreateRow(
7);
row8.CreateCell(
0).SetCellValue("收入");
row8.CreateCell(
1).SetCellValue("税率");
HSSFRow row9 = sheet1.CreateRow(
8);
row9.CreateCell(
0).SetCellValue(7800);
row9.CreateCell(
1).SetCellFormula("LOOKUP(A9,$A$2:$A$6,$C$2:$C$6)");
这是一个根据工资查询相应税率的例子。我们首先创建了不同工资区间对应税率的字典,然后根据具体的工资在字典中找出对应的税率。执行后生成的Excel如下:
下面对各参数加以说明:第一个参数:需要查找的内容,本例中指向A9单元格,也就是7800;第二个参数:比较对象区域,本例中的工资需要与$A$2:$A$6中的各单元格中的值进行比较;第三个参数:查找结果区域,如果匹配到会将此区域中对应的数据返回。如本例中返回$C$2:$C$6中对应的值。可能有人会问,字典中没有7800对应的税率啊,那么Excel中怎么匹配的呢?答案是模糊匹配,并且LOOKUP函数只支持模糊匹配。Excel会在$A$2:$A$6中找小于7800的最大值,也就是A3对应的3001,然后将对应的$C$2:$C$6区域中的C3中的值返回,这就是最终结果0.2的由来。这下明白了吧:)
VLOOKUP另外,LOOKUP函数还有一位大哥--VLOOKUP。两兄弟有很多相似之处,但大哥本领更大。Vlookup用对比数与一个“表”进行对比,而不是Lookup函数的某1列或1行,并且Vlookup可以选择采用精确查询或是模糊查询方式,而Lookup只有模糊查询。将上例中设置公式的代码换成:
row9.CreateCell(1).SetCellFormula("VLOOKUP(A9,$A$2:$C$6,3,TRUE)");
执行后生成的Excel样式如下:
第一个参数:需要查找的内容,这里是A9单元格;第二个参数:需要比较的表,这里是$A$2:$C$6,注意VLOOKUP匹配时只与表中的第一列进行匹配。第三个参数:匹配结果对应的列序号。这里要对应的是税率列,所以为3。第四个参数:指明是否模糊匹配。例子中的TRUE表示模糊匹配,与上例中一样。匹配到的是第三行。如果将此参数改为FALSE,因为在表中的第1列中找不到7800,所以会报“#N/A”的计算错误。
另外,还有与VLOKUP类似的HLOOKUP。不同的是VLOOKUP用于在表格或数值数组的首列查找指定的数值,并由此返回表格或数组当前行中指定列处的数值。而HLOOKUP用于在表格或数值数组的首行查找指定的数值,并由此返回表格或数组当前列中指定行处的数值。读者可以自已去尝试。
2.3.8用NPOI操作EXCEL--随机数函数
我们知道,在大多数编程语言中都有随机数函数。在Excel中,同样存在着这样一个函数—RAND()函数,用于生成随机数。先来看一个最简单的例子:
HSSFSheet sheet1 = hssfworkbook.CreateSheet("Sheet1");
sheet1.CreateRow(
0).CreateCell(0).SetCellFormula("RAND()");
RAND()函数将返回一个0-1之间的随机数,执行后生成的Excel文件如下:
这只是最简单直接的RAND()函数的应用,只要我们稍加修改,就可以作出很多种变换。如取0-100之前的随机整数,可设置公式为:
sheet1.CreateRow(0).CreateCell(0).SetCellFormula("int(RAND()*100)");
取10-20之间的随机实数,可设置公式为:
sheet1.CreateRow(0).CreateCell(0).SetCellFormula("rand()*(20-10)+10");
随机小写字母:
sheet1.CreateRow(0).CreateCell(0).SetCellFormula("CHAR(INT(RAND()*26)+97)");
随机大写字母:
sheet1.CreateRow(0).CreateCell(0).SetCellFormula("CHAR(INT(RAND()*26)+65)")
随机大小写字母:
sheet1.CreateRow(0).CreateCell(0).SetCellFormula("CHAR(INT(RAND()*26)+if(INT(RAND()*2)=0,65,97))");
上面几例中除了用到RAND函数以外,还用到了CHAR函数用来将ASCII码换为字母,INT函数用来取整。值得注意的是INT函数不会四舍五入,无论小数点后是多少都会被舍去。这里只是RAND函数的几个简单应用,还有很多随机数的例子都可以根据这些,再结合不同的其它函数引申出来。
2.3.9用NPOI操作EXCEL--通过NPOI获得公式的返回值
前面我们学习了通过NPOI向Excel中设置公式,那么有些读者可能会问:“NPOI能不能获取公式的返回值呢?”,答案是可以!一、获取模板文件中公式的返回值如在D盘中有一个名为text.xls的Excel文件,其内容如下:
注意C1单元格中设置的是公式“$A1*$B1”,而不是值“12”。利用NPOI,只需要写简单的几句代码就可以取得此公式的返回值:
HSSFWorkbook wb =newHSSFWorkbook(newFileStream("d:/test.xls",FileMode.Open));
HSSFCell cell = wb.GetSheet(
"Sheet1").GetRow(0).GetCell(2);
System.Console.WriteLine(cell.NumericCellValue);
输出结果为:
可见NPOI成功的“解析”了此.xls文件中的公式。注意NumericCellValue属性会自动根据单元格的类型处理,如果为空将返0,如果为数值将返回数值,如果为公式将返回公式计算后的结果。单元格的类型可以通过CellType属性获取。
二、获取NPOI生成的Excel文件中公式的返回值上例中是从一个已经存在的Excel文件中获取公式的返回值,那么如果Excel文件是通过NPOI创建的,直接用上面的方法获取,可能得不到想要的结果。如:
1HSSFWorkbook hssfworkbook =newHSSFWorkbook();
2HSSFSheet sheet1 = hssfworkbook.CreateSheet("Sheet1");
3HSSFRow row = sheet1.CreateRow(0);
4row.CreateCell(0).SetCellValue(3);
5row.CreateCell(1).SetCellValue(4);
6HSSFCell cell = row.CreateCell(2);
78cell.SetCellFormula("$A1+$B1");
9System.Console.WriteLine(cell.NumericCellValue);
执行上面代码,将输出结果“0”,而不是我们想要的结果“7”。那么将如何解决呢?这时要用到HSSFFormulaEvaluator类。在第8行后加上这两句就可以了:
HSSFFormulaEvaluator e =newHSSFFormulaEvaluator(hssfworkbook);
cell = e.EvaluateInCell(cell);
运行结果如下:
2.4.1用NPOI操作EXCEL--画线
之所有说NPOI强大,是因为常用的Excel操作她都可以通过编程的方式完成。这节开始,我们开始学习NPOI的画图功能。先从最简单的开始,画一条直线:
对应的代码为:
HSSFSheet sheet1 = hssfworkbook.CreateSheet("Sheet1");
HSSFPatriarch patriarch = sheet1.CreateDrawingPatriarch();
HSSFClientAnchor a1 =
newHSSFClientAnchor(255,125,1023,150,0,0,2,2);
HSSFSimpleShape line1 = patriarch.CreateSimpleShape(a1);
line1.ShapeType = HSSFSimpleShape.OBJECT_TYPE_LINE;
line1.LineStyle = HSSFShape.LINESTYLE_SOLID;
//在NPOI中线的宽度12700表示1pt,所以这里是0.5pt粗的线条。line1.LineWidth =6350;
通常,利用NPOI画图主要有以下几个步骤:
1.
创建一个Patriarch;
2.
创建一个Anchor,以确定图形的位置;
3.
调用Patriarch创建图形;
4.
设置图形类型(直线,矩形,圆形等)及样式(颜色,粗细等)。
关于HSSFClientAnchor(dx1,dy1,dx2,dy2,col1,row1,col2,row2)的参数,有必要在这里说明一下:
dx1
:起始单元格的x偏移量,如例子中的255表示直线起始位置距A1单元格左侧的距离;
dy1
:起始单元格的y偏移量,如例子中的125表示直线起始位置距A1单元格上侧的距离;
dx2
:终止单元格的x偏移量,如例子中的1023表示直线起始位置距C3单元格左侧的距离;
dy2
:终止单元格的y偏移量,如例子中的150表示直线起始位置距C3单元格上侧的距离;
col1
:起始单元格列序号,从0开始计算;
row1
:起始单元格行序号,从0开始计算,如例子中col1=0,row1=0就表示起始单元格为A1;
col2
:终止单元格列序号,从0开始计算;
row2
:终止单元格行序号,从0开始计算,如例子中col2=2,row2=2就表示起始单元格为C3;
最后,关于LineStyle属性,有如下一些可选值,对应的效果分别如图所示:
2.4.2用NPOI操作EXCEL--画矩形
上一节我们讲了NPOI中画图的基本步骤:
1.
创建一个Patriarch;
2.
创建一个Anchor,以确定图形的位置;
3.
调用Patriarch创建图形;
4.
设置图形类型(直线,矩形,圆形等)及样式(颜色,粗细等)。
这一节我们将按照这个步骤创建一个矩形。废话少说,上代码:
HSSFSheet sheet1 = hssfworkbook.CreateSheet("Sheet1");
HSSFPatriarch patriarch = sheet1.CreateDrawingPatriarch();
HSSFClientAnchor a1 =
newHSSFClientAnchor(255,125,1023,150,0,0,2,2);
HSSFSimpleShape rec1 = patriarch.CreateSimpleShape(a1);
//此处设置图形类型为矩形rec1.ShapeType = HSSFSimpleShape.OBJECT_TYPE_RECTANGLE;
//设置填充色rec1.SetFillColor(125,125,125);
//设置边框样式rec1.LineStyle = HSSFShape.LINESTYLE_DASHGEL;
//设置边框宽度rec1.LineWidth =25400;
//设置边框颜色rec1.SetLineStyleColor(100,0,100);
代码执行效果:
其中SetFillColor和SetLineStyleColor函数的三个参数分别是RGB三色值,具体表示什么颜色,找个Photoshop试试:)关于HSSFClientAnchor参数说明、边框样式,边框宽度的说明可以参见前一篇博文:
http://www.cnblogs.com/atao/archive/2009/09/13/1565645.html
2.4.3用NPOI操作EXCEL--画圆形
前面我们学习了NPOI中的画简单直线和矩形的功能,今天我们一起学习一下它支持的另一种简单图形--圆形。同样,按照前面所讲的绘图“四步曲”:
1.
创建一个Patriarch;
2.
创建一个Anchor,以确定图形的位置;
3.
调用Patriarch创建图形;
4.
设置图形类型(直线,矩形,圆形等)及样式(颜色,粗细等)。还是以例子加以说明:
HSSFSheet sheet1 = hssfworkbook.CreateSheet("Sheet1");
HSSFPatriarch patriarch = sheet1.CreateDrawingPatriarch();
HSSFClientAnchor a1 =
newHSSFClientAnchor(0,0,1023,0,0,0,1,3);
HSSFSimpleShape rec1 = patriarch.CreateSimpleShape(a1);
rec1.ShapeType = HSSFSimpleShape.OBJECT_TYPE_OVAL;
rec1.SetFillColor(
125,125,125);
rec1.LineStyle = HSSFShape.LINESTYLE_DASHGEL;
rec1.LineWidth =
12700;
rec1.SetLineStyleColor(
100,0,100);
WriteToFile();
这里rec1.ShapeType =HSSFSimpleShape.OBJECT_TYPE_OVAL;表示图形为椭圆。适当调整HSSFClientAnchor的各参数可以得到圆形。关于HSSFClientAnchor构造函数和边框、填充色等前两节都有介绍,这里不再重述。详情情见:画矩形和画线。
上面代码执行生成的Excel如下:
2.4.4用NPOI操作EXCEL--画Grid
在NPOI中,本身没有画Grid的方法。但我们知道Grid其实就是由横线和竖线构成的,所在我们可以通过画线的方式来模拟画Grid。
HSSFSheet sheet1 = hssfworkbook.CreateSheet("Sheet1");
HSSFRow row = sheet1.CreateRow(
2);
row.CreateCell(
1);
row.HeightInPoints =
240;
sheet1.SetColumnWidth(
2,9000);
intlinesCount =20;
HSSFPatriarch patriarch = sheet1.CreateDrawingPatriarch();
//因为HSSFClientAnchor中dx只能在0-1023之间,dy只能在0-255之间,所以这里采用比例的方式doublexRatio =1023.0/ (linesCount*10);
doubleyRatio =255.0/ (linesCount*10);
//画竖线intx1 =0;
inty1 =0;
intx2 =0;
inty2 =200;
for(inti =0; i < linesCount; i++)
{
HSSFClientAnchor a2 =
newHSSFClientAnchor();
a2.SetAnchor((
short)2,2, (int)(x1 * xRatio), (int)(y1 * yRatio),
(
short)2,2, (int)(x2 * xRatio), (int)(y2 * yRatio));
HSSFSimpleShape shape2 = patriarch.CreateSimpleShape(a2);
shape2.ShapeType = (HSSFSimpleShape.OBJECT_TYPE_LINE);
x1 +=
10;
x2 +=
10;
}
//画横线x1 =0;
y1 =
0;
x2 =
200;
y2 =
0;
for(inti =0; i < linesCount; i++)
{
HSSFClientAnchor a2 =
newHSSFClientAnchor();
a2.SetAnchor((
short)2,2, (int)(x1 * xRatio), (int)(y1 * yRatio),
(
short)2,2, (int)(x2 * xRatio), (int)(y2 * yRatio));
HSSFSimpleShape shape2 = patriarch.CreateSimpleShape(a2);
shape2.ShapeType = (HSSFSimpleShape.OBJECT_TYPE_LINE);
y1 +=
10;
y2 +=
10;
}
请注意HSSFClientAnchor对象中的dx只能取0-1023之间的数,dy只能取0-255之间的数。我们可以理解为是将单元格的宽和高平分成了1023和255份,设置dx和dy时相当于按比例取对应的座标。最终生成的Excel如下:
2.4.5用NPOI操作EXCEL--插入图片
我们知道,在Excel中是可以插入图片的。操作菜单是“插入->图片”,然后选择要插入图片,可以很容易地在Excel插入图片。同样,在NPOI中,利用代码也可以实现同样的效果。在NPOI中插入图片的方法与画图的方法有点类似:
//add picture data to this workbook.
byte[] bytes = System.IO.File.ReadAllBytes(@"D:\MyProject\NPOIDemo\ShapeImage\image1.jpg");
intpictureIdx = hssfworkbook.AddPicture(bytes, HSSFWorkbook.PICTURE_TYPE_JPEG);
//create sheet
HSSFSheet sheet = hssfworkbook.CreateSheet("Sheet1");
// Create the drawing patriarch. This is the top level container for all shapes.
HSSFPatriarch patriarch = sheet.CreateDrawingPatriarch();
//add a picture
HSSFClientAnchor anchor =newHSSFClientAnchor(0,0,1023,0,0,0,1,3);
HSSFPicture pict = patriarch.CreatePicture(anchor, pictureIdx);
与画简单图形不同的是,首先要将图片读入到byte数组,然后添加到workbook中;最后调用的是patriarch.CreatePicture(anchor, pictureIdx)方法显示图片,而不是patriarch.CreateSimpleShape(anchor)方法。上面这段代码执行后生成的Excel文件样式如下:
我们发现,插入的图片被拉伸填充在HSSFClientAnchor指定的区域。有时可能我们并不需要拉伸的效果,怎么办呢?很简单,在最后加上这样一句用来自动调节图片大小:
pict.Resize();
添加代码后再执行上述代码,生成的Excel样式如下:
图片已经自动伸缩到原始大小了。
NPOI 1.2教程- 2.5打印相关设置
作者:Tony Qu
NPOI官方网站:http://npoi.codeplex.com/
打印设置主要包括方向设置、缩放、纸张设置、页边距等。NPOI 1.2支持大部分打印属性,能够让你轻松满足客户的打印需要。
首先是方向设置,Excel支持两种页面方向,即纵向和横向。
在NPOI中如何设置呢?你可以通过HSSFSheet.PrintSetup.Landscape来设置,Landscape是布尔类型的,在英语中是横向的意思。如果Landscape等于true,则表示页面方向为横向;否则为纵向。
接着是缩放设置,
这里的缩放比例对应于HSSFSheet.PrintSetup.Scale,而页宽和页高分别对应于HSSFSheet.PrintSetup.FitWidth和HSSFSheet.PrintSetup.FitHeight。要注意的是,这里的PrintSetup.Scale应该被设置为0-100之间的值,而不是小数。
接下来就是纸张设置了,对应于HSSFSheet.PrintSetup.PaperSize,但这里的PaperSize并不是随便设置的,而是由一些固定的值决定的,具体的值与对应的纸张如下表所示:
值纸张
1US Letter 8 1/2 x 11 in
2USLetter Small 8 1/2 x 11 in
3US Tabloid 11 x 17 in
4US Ledger 17 x 11 in
5US Legal 8 1/2 x 14 in
6US Statement 5 1/2 x 8 1/2 in
7US Executive 7 1/4 x 10 1/2 in
8A3 297 x 420 mm
9A4 210 x 297 mm
10A4 Small 210 x 297 mm
11A5 148 x 210 mm
12B4 (JIS) 250 x 354
13B5 (JIS) 182 x 257 mm
14Folio 8 1/2 x 13 in
15Quarto 215 x 275 mm
1610 x 14 in
1711 x 17 in
18US Note 8 1/2 x 11 in
19US Envelope #9 3 7/8 x 8 7/8
20US Envelope #10 4 1/8 x 9 1/2
21US Envelope #11 4 1/2 x 10 3/8
22US Envelope #12 4 \276 x 11
23US Envelope #14 5 x 11 1/2
24C size sheet
25D size sheet
26E size sheet
27Envelope DL 110 x 220mm
28Envelope C5 162 x 229 mm
29Envelope C3 324 x 458 mm
30Envelope C4 229 x 324 mm
31Envelope C6 114 x 162 mm
32Envelope C65 114 x 229 mm
33Envelope B4 250 x 353 mm
34Envelope B5 176 x 250 mm
35Envelope B6 176 x 125 mm
36Envelope 110 x 230 mm
37US Envelope Monarch 3.875 x 7.5 in
386 3/4 US Envelope 3 5/8 x 6 1/2 in
39US Std Fanfold 14 7/8 x 11 in
40German Std Fanfold 8 1/2 x 12 in
41German Legal Fanfold 8 1/2 x 13 in
42B4 (ISO) 250 x 353 mm
43Japanese Postcard 100 x 148 mm
449 x 11 in
4510 x 11 in
4615 x 11 in
47Envelope Invite 220 x 220 mm
48RESERVED--DO NOT USE
49RESERVED--DO NOT USE
50US Letter Extra 9 \275 x 12 in
51US Legal Extra 9 \275 x 15 in
52US Tabloid Extra 11.69 x 18 in
53A4 Extra 9.27 x 12.69 in
54Letter Transverse 8 \275 x 11 in
55A4 Transverse 210 x 297 mm
56Letter Extra Transverse 9\275 x 12 in
57SuperA/SuperA/A4 227 x 356 mm
58SuperB/SuperB/A3 305 x 487 mm
59US Letter Plus 8.5 x 12.69 in
60A4 Plus 210 x 330 mm
61A5 Transverse 148 x 210 mm
62B5 (JIS) Transverse 182 x 257 mm
63A3 Extra 322 x 445 mm
64A5 Extra 174 x 235 mm
65B5 (ISO) Extra 201 x 276 mm
66A2 420 x 594 mm
67A3 Transverse 297 x 420 mm
68A3 Extra Transverse 322 x 445 mm
69Japanese Double Postcard 200 x 148 mm
70A6 105 x 148 mm
71Japanese Envelope Kaku #2
72Japanese Envelope Kaku #3
73Japanese Envelope Chou #3
74Japanese Envelope Chou #4
75Letter Rotated 11 x 8 1/2 11 in
76A3 Rotated 420 x 297 mm
77A4 Rotated 297 x 210 mm
78A5 Rotated 210 x 148 mm
79B4 (JIS) Rotated 364 x 257 mm
80B5 (JIS) Rotated 257 x 182 mm
81Japanese Postcard Rotated 148 x 100 mm
82Double Japanese Postcard Rotated 148 x 200 mm
83A6 Rotated 148 x 105 mm
84Japanese Envelope Kaku #2 Rotated
85Japanese Envelope Kaku #3 Rotated
86Japanese Envelope Chou #3 Rotated
87Japanese Envelope Chou #4 Rotated
88B6 (JIS) 128 x 182 mm
89B6 (JIS) Rotated 182 x 128 mm
9012 x 11 in
91Japanese Envelope You #4
92Japanese Envelope You #4 Rotated
93PRC 16K 146 x 215 mm
94PRC 32K 97 x 151 mm
95PRC 32K(Big) 97 x 151 mm
96PRC Envelope #1 102 x 165 mm
97PRC Envelope #2 102 x 176 mm
98PRC Envelope #3 125 x 176 mm
99PRC Envelope #4 110 x 208 mm
100PRC Envelope #5 110 x 220 mm
101PRC Envelope #6 120 x 230 mm
102PRC Envelope #7 160 x 230 mm
103PRC Envelope #8 120 x 309 mm
104PRC Envelope #9 229 x 324 mm
105PRC Envelope #10 324 x 458 mm
106PRC 16K Rotated
107PRC 32K Rotated
108PRC 32K(Big) Rotated
109PRC Envelope #1 Rotated 165 x 102 mm
110PRC Envelope #2 Rotated 176 x 102 mm
111PRC Envelope #3 Rotated 176 x 125 mm
112PRC Envelope #4 Rotated 208 x 110 mm
113PRC Envelope #5 Rotated 220 x 110 mm
114PRC Envelope #6 Rotated 230 x 120 mm
115PRC Envelope #7 Rotated 230 x 160 mm
116PRC Envelope #8 Rotated 309 x 120 mm
117PRC Envelope #9 Rotated 324 x 229 mm
118PRC Envelope #10 Rotated 458 x 324 mm
(此表摘自《Excel Binary File Format (.xls) Structure Specification.pdf》)
HSSFSheet下面定义了一些xxxx_PAPERSIZE的常量,但都是非常常用的纸张大小,如果满足不了你的需要,可以根据上表自己给PaperSize属性赋值。所以,如果你要设置纸张大小可以用这样的代码:
HSSFSheet.PrintSetup.PaperSize=HSSFSheet.A4_PAPERSIZE;
或
HSSFSheet.PrintSetup.PaperSize=9;(A4 210*297mm)
再下来就是打印的起始页码,它对应于HSSFSheet.PrintSetup.PageStart和HSSFSheet.PrintSetup.UsePage,如果UsePage=false,那么就相当于“自动”,这时PageStart不起作用;如果UsePage=true,PageStart才会起作用。所以在设置PageStart之前,必须先把UsePage设置为true。
“打印”栏中的“网格线”设置对应于HSSFSheet.IsPrintGridlines,请注意,这里不是HSSFSheet.PrintSetup下面,所以别搞混了。这里之所以不隶属于PrintSetup是由底层存储该信息的record决定的,底层是把IsGridsPrinted放在GridsetRecord里面的,而不是PrintSetupRecord里面的,尽管界面上是放在一起的。另外还有一个HSSFSheet.IsGridsPrinted属性,这个属性对应于底层的gridset Record,但这个record是保留的,从微软的文档显示没有任何意义,所以这个属性请不要去设置。
“单色打印”则对应于HSSFSheet.PrintSetup.NoColors,这是布尔类型的,值为true时,表示单色打印。
“草稿品质”对应于HSSFSheet.PrintSetup.IsDraft,也是布尔类型的,值为true时,表示用草稿品质打印。
这里的打印顺序是由HSSFSheet.PrintSetup.LeftToRight决定的,它是布尔类型的,当为true时,则表示“先行后列”;如果是false,则表示“先列后行”。
在NPOI 1.2中,“行号列标”、“批注”和“错误单元格打印为”、“页边距”暂不支持,将在以后的版本中支持。
有关打印的范例可以参考NPOI 1.2正式版中的SetPrintSettingsInXls项目。
2.6.1用NPOI操作EXCEL--调整表单显示比例
在Excel中,可以通过调整右下角的滚动条来调整Sheet的显示比例。如图:
在NPOI中,也能通过代码实现这样的功能,并且代码非常简单:
HSSFSheet sheet1 = hssfworkbook.CreateSheet("Sheet1");
sheet1.CreateRow(
0).CreateCell(0).SetCellValue("This is a test.");
//50% zoom
sheet1.SetZoom(1,2);
我们发现,SetZoom有两个参数。其中第一个参数表示缩放比例的分子,第二个参数表示缩放比例的分母,所以SetZoom(1,2)就表示缩小到1/2,也就是50%。代码执行后生成的Excel样式如下:
如果将SetZoom的参数改成(2,1),代码执行后生成的Excel样式如下,表示扩大两倍:
2.6.2用NPOI操作EXCEL--设置密码
有时,我们可能需要某些单元格只读,如在做模板时,模板中的数据是不能随意让别人改的。在Excel中,可以通过“审阅->保护工作表”来完成,如下图:
那么,在NPOI中有没有办法通过编码的方式达到这一效果呢?答案是肯定的。
HSSFSheet sheet1 = hssfworkbook.CreateSheet("Sheet1");
HSSFRow row1 = sheet1.CreateRow(
0);
HSSFCell cel1 = row1.CreateCell(
0);
HSSFCell cel2 = row1.CreateCell(
1);
HSSFCellStyle unlocked = hssfworkbook.CreateCellStyle();
unlocked.IsLocked =
false;
HSSFCellStyle locked = hssfworkbook.CreateCellStyle();
locked.IsLocked =
true;
cel1.SetCellValue(
"没被锁定");
cel1.CellStyle = unlocked;
cel2.SetCellValue(
"被锁定");
cel2.CellStyle = locked;
sheet1.ProtectSheet(
"password");
正如代码中所看到的,我们通过设置CellStype的ISLocked为True,表示此单元格将被锁定。相当于在Excel中执行了如下操作:
然后通过ProtectSheet设置密码。
执行结果如下:
没被锁定的列可以任意修改。
被锁定的列不能修改。
输入密码可以解除锁定。
NPOI 1.2教程-组合行、列
作者:Tony Qu
NPOI官方网站:http://npoi.codeplex.com/
Excel 2007中有一个面板是专门用于设置组合功能的,叫做“分级显示”面板,如下所示:
可能我们在过去生成Excel文件的时候根本不会用这个功能,也没办法用,因为cvs法和html法没办法控制这些东西。这里简单的介绍一下什么叫做组合:
组合分为行组合和列组合,所谓行组合,就是让n行组合成一个集合,能够进行展开和合拢操作,在Excel中显示如下:
图中左侧就是用于控制行组合折叠的图标,图中上部就是用于控制列组合的,是不是有点像TreeView中的折叠节点?很多时候由于数据太多,为了让用户对于大量数据一目了然,我们可以使用行列组合来解决显示大纲,这和Visual Studio里面的region的概念是类似的。
细心的朋友可能已经注意到了,我们其实可以对一行做多次组合操作,这就是分级显示的概念,图中就把行2-3分为2个组合,第2行到第4行为一个组合,第2行到第5行一个组合,所以是分两级。
在NPOI中,要实现分组其实并不难,你只需要调用HSSFSheet.GroupRow和HSSFSheet.GroupColumn这两个方法就可以了。
首先我们来看HSSFSheet.GroupRow,GroupRow有2个参数,分别是fromRow和toRow,表示起始行号和结束行号,这些行号都是从0开始算起的。
HSSFWorkbookhssfworkbook =newHSSFWorkbook();
HSSFSheet s =hssfworkbook.CreateSheet("Sheet1");
s.GroupRow(1,3);
上面的代码把第2行到第4行做了组合。
要组合列,其实代码很相似,如下所示:
s.GroupColumn(1,3)
上面的代码把B至D列做了组合。
正如上图中Excel的“分级显示”面板所示,有“组合”,也一定有“取消组合”,NPOI中你可以用HSSFSheet.UngroupRow和HSSFSheet.UngroupColumn,参数和GroupXXX是一样的,如果要取消第2到第4行的组合,就可以用下面的代码:
s.UngroupColumn(1,3)
相关范例请见NPOI 1.2正式版中的GroupRowAndColumnInXls项目。
2.6.4用NPOI操作EXCEL--锁定列
在Excel中,有时可能会出现列数太多或是行数太多的情况,这时可以通过锁定列来冻结部分列,不随滚动条滑动,方便查看。在Excel中设置冻结列的方法如下:
同样,利用NPOI,通过代码也能实现上面的效果:
HSSFSheet sheet1 = hssfworkbook.CreateSheet("Sheet1");
HSSFRow row1 = sheet1.CreateRow(
0);
row1.CreateCell(
0).SetCellValue("冻结列");
sheet1.CreateFreezePane(
1,0,1,0);
代码执行结果如下:
下面对CreateFreezePane的参数作一下说明:第一个参数表示要冻结的列数;第二个参数表示要冻结的行数,这里只冻结列所以为0;第三个参数表示右边区域可见的首列序号,从1开始计算;第四个参数表示下边区域可见的首行序号,也是从1开始计算,这里是冻结列,所以为0;
举例说明也许更好理解,将各参数设置为如下:
sheet1.CreateFreezePane(2,0,5,0);
得到的效果如下图:
注意图中C、D和E列默认是看不到的,滚动才看得到,这就是第三个参数5起了作用,是不是很好理解了呢:)
接下来,看一下冻结行的效果。将上面的代码稍作修改:
HSSFSheet sheet1 = hssfworkbook.CreateSheet("Sheet1");
HSSFRow row1 = sheet1.CreateRow(
0);
row1.CreateCell(
0).SetCellValue("冻结行");
sheet1.CreateFreezePane(
0,1,0,1);
执行后生成的Excel文件效果见下图:
那么,如果要行和列同时冻结该怎么做呢?聪明的你一定能想得到,呵呵~~
NPOI 1.2教程-显示/隐藏Excel网格线
作者:Tony Qu
NPOI官方网站:http://npoi.codeplex.com/
有些时候,我们需要网格线,而有些时候我们不需要,这取决于实际的业务需求。前两天inmegin兄就问我,怎么把网格给去掉,因为他们要把Excel文档当Word使,也许是因为Excel排版方便吧。
Excel中的网格线设置是以表(Sheet)为单位进行管理的,这也就意味着你可以让一个表显示网格线,而另一个表不显示,这是不冲突的。
在Excel 2007中,我们通常用“工作表选项”面板来设置这个属性:
在面板中,你会发现有2个多选框,一个是查看,一个是打印,也就是说Excel是把查看和打印网格线作为两个设置来处理的,存储的Record也是不同的。
在NPOI中,如果要让网格线在查看时显示/隐藏,你可以HSSFSheet.DisplayGridlines属性,默认值为true(这也是为什么默认情况下我们能够看到网格线)。下面的代码就是让网格线在查看时不可见的:
HSSFWorkbookhssfworkbook =newHSSFWorkbook();
HSSFSheet s1= hssfworkbook.CreateSheet("Sheet1");
s1.DisplayGridlines=false;
如果要在打印时显示/隐藏网格线,你可以用HSSFSheet.IsGridlinesPrinted属性,默认值为false(这就是默认情况下打印看不到网格线的原因)。代码和上面差不多:
s1.IsGridsPrinted=true;
上面的代码将在打印时显示网格线,打印的效果如下所示。
在此也提醒大家,如果这个Excel最终客户有打印意向,可别忘了把IsGridPrinted属性也设置上。
相关范例可以参考NPOI 1.2正式版中的DisplayGridlinesInXls项目。
2.6.6用NPOI操作EXCEL--设置初始视图的行、列
有些时候,我们可能希望生成的Excel文件在被打开的时候自动将焦点定位在某个单元格或是选中某个区域中。在NPOI中可以通过SetAsActiveCell和SetActiveCellRange等几个方法实现。
首先我们看一下设置初始视图中选中某个单元格的方法:
//use HSSFCell.SetAsActiveCell() to select B6 as the active column
HSSFSheet sheet1 = hssfworkbook.CreateSheet("Sheet A");
CreateCellArray(sheet1);
sheet1.GetRow(
5).GetCell(1).SetAsActiveCell();
//set TopRow and LeftCol to make B6 the first cell in the visible area
sheet1.TopRow =5;
sheet1.LeftCol =
1;
其中CreateCellArray(sheet1)方法用来写示范数据,其代码为(下同):
staticvoidCreateCellArray(HSSFSheet sheet)
{
for(inti =0; i <300; i++)
{
HSSFRow row=sheet.CreateRow(i);
for(intj =0; j <150; j++)
{
HSSFCell cell = row.CreateCell(j);
cell.SetCellValue(i*j);
}
}
}
生成的Excel打开时效果如下,注意B6为默认选中状态,TopRow和LeftCol设置B6为当前可见区域的第一个单元格:
如果不设置TopRow和LeftCol属性,默认的可见域的第一个单元格为A1,如下是另一种设置活动单元格的方法,但没有设置此Sheet的TopRow和LeftCol:
HSSFSheet sheet2 = hssfworkbook.CreateSheet("Sheet B");
sheet2.Sheet.SetActiveCell(
1,5);
对应生成的Excel显示为:
除了设置某个单元格为选中状态外,还NPOI可以设置某个区域为选中状态:
//use Sheet.SetActiveCellRange to select a cell range
HSSFSheet sheet3 = hssfworkbook.CreateSheet("Sheet C");
CreateCellArray(sheet3);
sheet3.Sheet.SetActiveCellRange(
2,5,1,5);
以上代码设置了Sheet C的选中区域为B3:F6:
还有更强大的,设置多个选中区域:
//use Sheet.SetActiveCellRange to select multiple cell ranges
HSSFSheet sheet4 = hssfworkbook.CreateSheet("Sheet D");
CreateCellArray(sheet4);
List cellranges =
newList();
cellranges.Add(
newCellRangeAddress8Bit(1,3,2,5));
cellranges.Add(
newCellRangeAddress8Bit(6,7,8,9));
sheet4.Sheet.SetActiveCellRange(cellranges,
1,6,9);
如果一个Excel文件中有多个Sheet,还可以通过如下语句设置打开时的初始Sheet:
hssfworkbook.ActiveSheetIndex =2;
2.6.7用NPOI操作EXCEL--数据有效性
在有些情况下(比如Excel引入),我们可能不允许用户在Excel随意输入一些无效数据,这时就要在模板中加一些数据有效性的验证。在Excel中,设置数据有效性的方步骤如下:(1)先选定一个区域;数据有效性”中设置数据有效性验证(如图)。à(2)在菜单“数据
同样,利用NPOI,用代码也可以实现:
HSSFSheet sheet1 = hssfworkbook.CreateSheet("Sheet1");
sheet1.CreateRow(
0).CreateCell(0).SetCellValue("日期列");
CellRangeAddressList regions1 =
newCellRangeAddressList(1,65535,0,0);
DVConstraint constraint1 = DVConstraint.CreateDateConstraint(DVConstraint.OperatorType.BETWEEN,
"1900-01-01","2999-12-31","yyyy-MM-dd");
HSSFDataValidation dataValidate1 =
newHSSFDataValidation(regions1, constraint1);
dataValidate1.CreateErrorBox(
"error","You must input a date.");
sheet1.AddValidationData(dataValidate1);
上面是一个在第一列要求输入1900-1-1至2999-12-31之间日期的有效性验证的例子,生成的Excel效果如下,当输入非法时将给出警告:
下面对刚才用到的几个方法加以说明:
CellRangeAddressList
类表示一个区域,构造函数中的四个参数分别表示起始行序号,终止行序号,起始列序号,终止列序号。所以第一列所在区域就表示为:
//所有序号都从零算起,第一行标题行除外,所以第一个参数是1,65535是一个Sheet的最大行数newCellRangeAddressList(1,65535,0,0);
另外,CreateDateConstraint的第一个参数除了设置成DVConstraint.OperatorType.BETWEEN外,还可以设置成如下一些值,大家可以自己一个个去试看看效果:
最后,dataValidate1.CreateErrorBox(title,text),用来创建出错时的提示信息。第一个参数表示提示框的标题,第二个参数表示提示框的内容。
理解了上面这些,创建一个整数类型的有效性验证也不难实现:
sheet1.CreateRow(0).CreateCell(1).SetCellValue("数值列");
CellRangeAddressList regions2 =
newCellRangeAddressList(1,65535,1,1);
DVConstraint constraint2 = DVConstraint.CreateNumericConstraint(DVConstraint.ValidationType.INTEGER,DVConstraint.OperatorType.BETWEEN,
"0","100");
HSSFDataValidation dataValidate2 =
newHSSFDataValidation(regions2, constraint2);
dataValidate2.CreateErrorBox(
"error","You must input a numeric between 0 and 100.");
sheet1.AddValidationData(dataValidate2);
生成的Excel效果为:
下一节我们将学习利用数据有效性创建下拉列表的例子。
2.6.8用NPOI操作EXCEL--生成下拉列表
上一节我们讲了简单的数据有效性验证,这一节我们学习一下数据有效性的另一个应用--下拉列表。在Excel中,并没有类似Web中的下拉控件,其下拉效果是通过数据有效性来实现的。设置步骤为:(1)选定一个要生成下拉列表的区域;(2)设置数据有效性为序列,并在来源中填充可选下拉的值,用“,”隔开(如图)。
对应的效果为:
同样,利用NPOI代码也可以实现上面的效果:
HSSFSheet sheet1 = hssfworkbook.CreateSheet("Sheet1");
CellRangeAddressList regions =
newCellRangeAddressList(0,65535,0,0);
DVConstraint constraint = DVConstraint.CreateExplicitListConstraint(
newstring[] {"itemA","itemB","itemC"});
HSSFDataValidation dataValidate =
newHSSFDataValidation(regions, constraint);
sheet1.AddValidationData(dataValidate);
下面对代码作一下简要说明:先设置一个需要提供下拉的区域,关于CellRangeAddressList构造函数参数的说明请参见上一节:
CellRangeAddressList regions =newCellRangeAddressList(0,65535,0,0);
然后将下拉项作为一个数组传给CreateExplicitListConstraint作为参数创建一个约束,根据要控制的区域和约束创建数据有效性就可以了。
但是这样会有一个问题:Excel中允许输入的序列来源长度最大为255个字符,也就是说当下拉项的总字符串长度超过255是将会出错。那么如果下拉项很多的情况下应该怎么处理呢?答案是通过引用的方式。步骤如下:先创建一个Sheet专门用于存储下拉项的值,并将各下拉项的值写入其中:
HSSFSheet sheet2 = hssfworkbook.CreateSheet("ShtDictionary");
sheet2.CreateRow(
0).CreateCell(0).SetCellValue("itemA");
sheet2.CreateRow(
1).CreateCell(0).SetCellValue("itemB");
sheet2.CreateRow(
2).CreateCell(0).SetCellValue("itemC");
然后定义一个名称,指向刚才创建的下拉项的区域:
HSSFName range = hssfworkbook.CreateName();
range.Reference =
"ShtDictionary!$A1:$A3";
range.NameName =
"dicRange";
最后,设置数据约束时指向这个名称而不是字符数组:
HSSFSheet sheet1 = hssfworkbook.CreateSheet("Sheet1");
CellRangeAddressList regions =
newCellRangeAddressList(0,65535,0,0);
DVConstraint constraint = DVConstraint.CreateFormulaListConstraint(
"dicRange");
HSSFDataValidation dataValidate =
newHSSFDataValidation(regions, constraint);
sheet1.AddValidationData(dataValidate);
执行这段代码,生成的Excel效果如下:
在名称管理器中会发现有一个名为"dicRange"的名称,指向"ShtDictionary!$A1:$A3"的下拉项区域:
在数据有效性中会发现来源变成了"=dicRange",指向上面定义的名称。而不是以前的"itemA,itemB,itemC":