POI 支持调用MS-Office 绘图工具进行图形的绘制。一张sheet页上的图形是按照有层级的图形组和图形来安排的。最顶层的图形是patriarch,它在sheet页上是不可见的。在开始绘制图形之前,您需要在HSSFSheet 对象中调用createPatriarch方法。调用这个方法会清除在该sheet页中储存的所有的图形信息。默认情况下只要这个方法不被调用,POI不会将图形数据清除。
要创建一个图形,您需要做以下几步:
1. 创建一个patriarch 对象
2. 创建一个锚点以供图形在sheet页上定位
3. 调用patriarch对象创建一个图形
4. 设置图形类型(直线,椭圆,矩形等等)
5. 设置图形的其他样式细节(例如:线条粗细等等)
HSSFPatriarch patriarch = sheet.createDrawingPatriarch();
a = new HSSFClientAnchor( 0, 0, 1023, 255, (short) 1, 0, (short) 1, 0 );
HSSFSimpleShape shape1 = patriarch.createSimpleShape(a1);
shape1.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE);
文本框的创建方式如下:
HSSFTextbox textbox1 = patriarch.createTextbox(
new HSSFClientAnchor(0,0,0,0,(short)1,1,(short)2,2));
textbox1.setString(new HSSFRichTextString("This is a test") );
在同一文本框中设置不同的字体样式也是可以实现的
HSSFFont font = wb.createFont();
font.setItalic(true);
font.setUnderline(HSSFFont.U_DOUBLE);
HSSFRichTextString string = new HSSFRichTextString("Woo!!!");
string.applyFont(2,5,font);
textbox.setString(string );
Just as can be done manually using Excel, it is possible to group shapes together. This is done by calling createGroup() and then creating the shapes using those groups.
如同Excel中可以手动设置组一样,调用createGroup()方法,用新建的组创建图形也可以实现。组中也可以嵌套其他组。
注意
任何一个组中必须至少包含两个不同图形或是其他的子组。
创建图片组可以参考下面的例子:
// 创建一个图片组.
HSSFShapeGroup group = patriarch.createGroup(
new HSSFClientAnchor(0,0,900,200,(short)2,2,(short)2,2));
//在图片组中创建多条直线.
HSSFSimpleShape shape1 = group.createShape(new HSSFChildAnchor(3,3,500,500));
shape1.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE);
( (HSSFChildAnchor) shape1.getAnchor() ).setAnchor((short)3,3,500,500);
HSSFSimpleShape shape2 = group.createShape(new HSSFChildAnchor((short)1,200,400,600));
shape2.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE);
如果您足够细心,您将会发下,在图形组中添加的图形使用的是一个新类型的锚点对象HSSFChildAnchor。这是因为新创建的组会有自己的坐标空间。在POI中,这个 坐标空间默认为(0,0,1023,255),但是您也可以根据自己的意愿进行修改。
myGroup.setCoordinates(10,10,20,20); // top-left, bottom-right
如果您在一个图片组中加入了另外一个图片组,同样该子图片组也有自己的坐标空间。
默认的图片演示看起来有些平常。为图形设置不同的样式也可以通过POI来实现。不过现在仅能支持以下几种图形样式改变:
l 变换填充色
l 去除填充色
l 改变线条粗细
l 改变线条样式 比如:虚线,点线等等
l 改变线条颜色
以下是如何实现
HSSFSimpleShape s = patriarch.createSimpleShape(a);
s.setShapeType(HSSFSimpleShape.OBJECT_TYPE_OVAL);
s.setLineStyleColor(10,10,10);
s.setFillColor(90,10,200);
s.setLineWidth(HSSFShape.LINEWIDTH_ONE_PT * 3);
s.setLineStyle(HSSFShape.LINESTYLE_DOTSYS);
虽然推荐使用本地POI命名来创建图形,但有时我们也希望调用标准AIP获得和外部库的兼容性。处于这目的我们对Graphics 和Graphics2d 类进行了扩充。
注意:
在开始使用之前,您需要知道Graphics2d对MS-office 绘图命令的支持不是很好,虽然Graphics类比起来对MS-office绘图命令更加兼容,但仍然差强人意。
所有的绘图指令都封装在HSSFShapeGroup类中。以下是它们的用法:
a = new HSSFClientAnchor( 0, 0, 1023, 255, (short) 1, 0, (short) 1, 0 );
group = patriarch.createGroup( a );
group.setCoordinates( 0, 0, 80 * 4 , 12 * 23 );
float verticalPointsPerPixel = a.getAnchorHeightInPoints(sheet) / (float)Math.abs(group.getY2() - group.getY1());
g = new EscherGraphics( group, wb, Color.black, verticalPointsPerPixel );
g2d = new EscherGraphics2d( g );
drawChemicalStructure( g2d );
首先我们做的是为我们将要进行的绘制创建一个组并设置它的坐标。接下来,我们计算出一个合理的 fontSizeMultipler 创建一个EscherGraphics对象。因为我们想得到的是Graphics2d对象,所以我们我们新建一个EscherGraphics2d对象并把它传入一个创建好的Graphics对象中。最后我们会通过一系列流程将它绘制成一个EscherGraphics2d对象。
在垂直方向上每个点的像素值还需要再深入说明一下。在将Graphics对象调用转化成Escher 对象调用中遇到的一个困难是,在Excel中没有明确的对绝对位置的像素定义。在Excel中,单元格的宽度是用“字符”宽度,高度是用“点”来度量的。不幸的是,在Excel中并没有明确的定义被用来度量的字符的类型。估计是由于Excel想在不同的平台上或是在同一平台上使用不同的字体造成的。
因为这些限制,我们必须要实现一个标准verticalPointsPerPixel 用来度量每个垂直方向点所占的像素。当您调用像是drawString()这样的方法时,所用到的字体的verticalPointsPerPixel度量值必须明确。
计算verticalPointsPerPixel值的公式如下:
multipler = groupHeightInPoints / heightOfGroup
图形组的高度可以通过简单的计算不同图形边界盒的Y轴坐标来得到。 获得图新组的高度也可以简单的调用以下这个方法:
HSSFClientAnchor.getAnchorHeightInPoints().
许多Graphic 类支持的方法还没有实现,现在已知实现的方法是:
现在还不支持的方法会调用POI日志机制返回并记录日志信息(默认为disabled)
提纲对将不同部分的信息聚合在一起非常重要。它可以用POI提供的API简单的这样实现:
Workbook wb = new HSSFWorkbook();
Sheet sheet1 = wb.createSheet("new sheet");
sheet1.groupRow( 5, 14 );
sheet1.groupRow( 7, 14 );
sheet1.groupRow( 16, 19 );
sheet1.groupColumn( (short)4, (short)7 );
sheet1.groupColumn( (short)9, (short)12 );
sheet1.groupColumn( (short)10, (short)11 );
FileOutputStream fileOut = new FileOutputStream(filename);
wb.write(fileOut);
fileOut.close();
折叠(或展开)一个提纲,可以用以下的方法:
sheet1.setRowGroupCollapsed( 7, true );
sheet1.setColumnGroupCollapsed( (short)4, true );
被选中的行或列必须包含一个已经创建好的组,可以是组内的任意位置。
图像是绘图支持的一部分。提价一张图片可以用最高级别的Drawing对象调用createPicture()。现在支持的图片格式有:
应当值得注意的是任何已经存在的绘图可能会因为您添加一张图片到sheet页上而被清除
//创建一个新的工作簿
Workbook wb = new XSSFWorkbook(); //or new HSSFWorkbook();
//为工作簿添加图片.
InputStream is = new FileInputStream("image1.jpeg");
byte[] bytes = IOUtils.toByteArray(is);
int pictureIdx = wb.addPicture(bytes, Workbook.PICTURE_TYPE_JPEG);
is.close();
CreationHelper helper = wb.getCreationHelper();
//创建sheet页
Sheet sheet = wb.createSheet();
// 创建顶层的Drawing对象,它是所有图形和图像的载体
Drawing drawing = sheet.createDrawingPatriarch();
//添加一个图片图形
ClientAnchor anchor = helper.createClientAnchor();
//设置图形左上角的位置
//然后调用 Picture 的resize() 方法,自动关联到新坐标
anchor.setCol1(3);
anchor.setRow1(2);
Picture pict = drawing.createPicture(anchor, pictureIdx);
//自动关联到新坐标
pict.resize();
//保存到工作簿
String file = "picture.xls";
if(wb instanceof XSSFWorkbook) file += "x";
FileOutputStream fileOut = new FileOutputStream(file);
wb.write(fileOut);
fileOut.close();
注意
Picture.resize() 现仅支持JPEG和PNG格式的图片,其他格式暂不支持
List lst = workbook.getAllPictures();
for (Iterator it = lst.iterator(); it.hasNext(); ) {
PictureData pict = (PictureData)it.next();
String ext = pict.suggestFileExtension();
byte[] data = pict.getData();
if (ext.equals("jpeg")){
FileOutputStream out = new FileOutputStream("pict.jpg");
out.write(data);
out.close();
}
}
关联范围是用一个名字代表一组单元格的方式。关联单元格是关联范围的下一级一组单元格中的一个。您可以用他们的关联范围创建或是得到对应的单元格。当要处理关联范围时可以用org.apache.poi.hssf.util.CellReference和org.apache.poi.hssf.util.AreaReference两个类(除了包名不一样外,在XSSF和HSSF中同样有这两个类)
创建管理范围/关联单元格
// 准备数据
String sname = "TestSheet", cname = "TestName", cvalue = "TestVal";
Workbook wb = new HSSFWorkbook();
Sheet sheet = wb.createSheet(sname);
sheet.createRow(0).createCell((short) 0).setCellValue(cvalue);
//1.用空间引用为一个单元格创建关联范围
Name namedCell = wb.createName();
namedCell.setNameName(cname);
String reference = sname+"!A1:A1"; // 空间引用
namedCell.setRefersToFormula(reference);
// 2.用单元格引用为一个单元格创建关联范围
Name namedCel2 = wb.createName();
namedCel2.setNameName(cname);
String reference = sname+"!A1"; //单元格引用
namedCel2.setRefersToFormula(reference);
// 3. 用空间引用为一组单元格创建关联范围
Name namedCel3 = wb.createName();
namedCel3.setNameName(cname);
String reference = sname+"!A1:C5"; // 空间引用
namedCel3.setRefersToFormula(reference);
// 4. 创建关联方程
Name namedCel4 = wb.createName();
namedCel4.setNameName("my_sum");
namedCel4.setRefersToFormula("SUM(sname+!$I$2:$I$6)");
从关联范围/关联单元格读取数据
// 准备数据
String cname = "TestName";
Workbook wb = getMyWorkbook(); // 获得工作簿
//获得关联范围
int namedCellIdx = wb.getNameIndex(cellName);
Name aNamedCell = wb.getNameAt(namedCellIdx);
AreaReference aref = new AreaReference(aNamedCell.getRefersToFormula());
CellReference[] crefs = aref.getAllReferencedCells();
for (int i=0; i<crefs.length; i++) {
Sheet s = wb.getSheet(crefs[i].getSheetName());
Row r = sheet.getRow(crefs[i].getRow());
Cell c = r.getCell(crefs[i].getCol());
//根据单元格数据格式取出单元格内容。。。。。。.
}
从不连续的关联范围中读取数据
// 准备数据
String cname = "TestName";
Workbook wb = getMyWorkbook(); // retrieve workbook
// 获得关联范围
// Will be something like "$C$10,$D$12:$D$14";
int namedCellIdx = wb.getNameIndex(cellName);
Name aNamedCell = wb.getNameAt(namedCellIdx);
//在关联范围中获得单元格并检测它的内容
//将会返回C10单元格和D12到D14单元格的空间引用
AreaReference[] arefs = AreaReference.generateContiguous(aNamedCell.getRefersToFormula());
for (int i=0; i<arefs.length; i++) {
// Only get the corners of the Area
// (use arefs[i].getAllReferencedCells() to get all cells)
CellReference[] crefs = arefs[i].getCells();
for (int j=0; j<crefs.length; j++) {
// Check it turns into real stuff
Sheet s = wb.getSheet(crefs[j].getSheetName());
Row r = s.getRow(crefs[j].getRow());
Cell c = r.getCell(crefs[j].getCol());
// 对此单元格进行相应的处理。。。。。。
}
}
注意:
当单元格被删除的时候,Excel并不会删除和它关联的关联范围。因此,在工作簿中会存在关联范围指向不存在的单元格的情况。在创建空间引用时应该先验证两者之间的关联引用是否正确。
if(name.isDeleted()){
//关联范围指向一个不存在的单元格
} else {
AreaReference ref = new AreaReference(name.getRefersToFormula());
}
注释是不同于单元格的内容是附属于或者从属与单元格的富文本。注释的内容是独立于单元格独自存储的,并且是在绘制对象中展示的(比如一个文本框),因此它既独立于单元格同时又与单元格紧密联系。
Workbook wb = new XSSFWorkbook(); //or new HSSFWorkbook();
CreationHelper factory = wb.getCreationHelper();
Sheet sheet = wb.createSheet();
Cell cell = sheet.createRow(3).createCell(5);
cell.setCellValue("F4");
我的博客地址:www.aitawo.com