使用Apache POI(Java)在XLSX中创建复选框 [英] Creating a checkbox in XLSX using Apache POI (Java)

查看:766
本文介绍了使用Apache POI(Java)在XLSX中创建复选框的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要在XSSFSheet中创建一个Excel复选框,但是在Java Apache POI库(4.0.1)中,我没有发现任何明显的类/方法,也没有任何示例.有什么建议吗?

I need to create an Excel checkbox in an XSSFSheet, but I have found no obvious classes/methods for doing so in the Java Apache POI library (4.0.1), nor any examples. Any suggestions?

推荐答案

Microsoft Excel中可能有两种控件.有旧版表单控件和ActiveX控件.创建遗留表单控件将是可能的. ActiveX控件要复杂得多.

There are two types of controls possible in Microsoft Excel. There are the legacy form controls and ActiveX controls. Creating legacy form controls would be possible. ActiveX controls wold be much more complex.

旧版表单控件存储在每张VML图纸中. Apache poi具有 XSSFVMLDrawing 之所以已经分类,是因为单元格注释也部分存储在VML绘图中.但是在apache poi中,该类通常不完整,并且设置了其方法的可访问性,因此该类无法轻松扩展.似乎apache poi开发人员经常明确希望阻止其类的扩展.

The legacy form controls are stored in VML drawings per sheet. Apache poi has a XSSFVMLDrawing class already because cell comments also are partially stored in VML drawings. But as often in apache poi the class is not complete and the accessibility of it's methods is set so that the class cannot easy extended. Seems as if apache poi developers often explicitly wants to prevent extension of their classes.

对于旧版Checkbox控件,我们需要一个复选框形状类型,然后在此VML绘图中需要复选框形状.

For legacy Checkbox controls we need a checkbox shape type and then checkbox shapes in this VML drawing.

以下代码创建两个旧的复选框.

Following code creates two legacy checkboxes.

方法XSSFVMLDrawing getVMLDrawing(XSSFSheet sheet)从图纸中获取VML绘图,或者如果尚不存在,则创建一个新的绘图.

The method XSSFVMLDrawing getVMLDrawing(XSSFSheet sheet) gets the VML drawing from the sheet or creates a new one if not already present.

方法void addCheckboxShapetype(XSSFVMLDrawing drawing)将新的复选框形状类型添加到图形中.

The method void addCheckboxShapetype(XSSFVMLDrawing drawing) adds a new checkbox shape type to the drawing.

方法void addCheckbox(XSSFVMLDrawing drawing, int col1, int dx1, int row1, int dy1, int col2, int dx2, int row2, int dy2, String label, boolean checked)将新的复选框形状添加到具有给定位置和标签的图形,并具有Checked元素,该元素在选中时包含1,在未选中时包含0.

The method void addCheckbox(XSSFVMLDrawing drawing, int col1, int dx1, int row1, int dy1, int col2, int dx2, int row2, int dy2, String label, boolean checked) adds a new checkbox shape to the drawing having the given position and label and has a Checked element which contains either 1 when checked or 0 when not checked.

完整示例:

import java.io.*;

import org.apache.poi.openxml4j.opc.*;
import org.apache.poi.ooxml.POIXMLDocumentPart;
import org.apache.xmlbeans.*;

import org.apache.poi.xssf.usermodel.*;

import com.microsoft.schemas.vml.*;
import com.microsoft.schemas.office.excel.CTClientData;

import java.lang.reflect.Field;
import javax.xml.namespace.QName;

import java.util.List;

class CreateExcelLegacyDrawingControls {

 private static XSSFVMLDrawing getVMLDrawing(XSSFSheet sheet) throws Exception {
  XSSFVMLDrawing drawing = null;
  if (sheet.getCTWorksheet().getLegacyDrawing() != null) { 
   String legacyDrawingId = sheet.getCTWorksheet().getLegacyDrawing().getId();
   drawing = (XSSFVMLDrawing)sheet.getRelationById(legacyDrawingId);
  } else {
   int drawingNumber = sheet.getPackagePart().getPackage()
    .getPartsByContentType(XSSFRelation.VML_DRAWINGS.getContentType()).size() + 1;
   POIXMLDocumentPart.RelationPart rp = 
    sheet.createRelationship(XSSFRelation.VML_DRAWINGS, XSSFFactory.getInstance(), drawingNumber, false);
   drawing = rp.getDocumentPart();
   String rId = rp.getRelationship().getId();
   sheet.getCTWorksheet().addNewLegacyDrawing().setId(rId);
  }
  return drawing;
 }

 private static void addCheckboxShapetype(XSSFVMLDrawing drawing) throws Exception {
  String shapeTypeId = "_x0000_t201";
  CTShapetype shapetype = CTShapetype.Factory.newInstance();
  shapetype.setId(shapeTypeId);
  shapetype.setCoordsize("21600,21600");
  shapetype.setSpt(201);
  shapetype.setPath2("m,l,21600r21600,l21600,xe");

  Field _items = XSSFVMLDrawing.class.getDeclaredField("_items");
  _items.setAccessible(true);
  @SuppressWarnings("unchecked") //we know the problem and expect runtime error if it possibly occurs
  List<XmlObject> items = (List<XmlObject>)_items.get(drawing);

  Field _qnames = XSSFVMLDrawing.class.getDeclaredField("_qnames");
  _qnames.setAccessible(true);
  @SuppressWarnings("unchecked") //we know the problem and expect runtime error if it possibly occurs
  List<QName> qnames = (List<QName>)_qnames.get(drawing);

  items.add(shapetype);
  qnames.add(new QName("urn:schemas-microsoft-com:vml", "shapetype"));
 }

 private static void addCheckbox(XSSFVMLDrawing drawing,
  int col1, int dx1, int row1, int dy1, int col2, int dx2, int row2, int dy2, 
  String label, boolean checked) throws Exception {

  String shapeTypeId = "_x0000_t201";

  Field _shapeId = XSSFVMLDrawing.class.getDeclaredField("_shapeId");
  _shapeId.setAccessible(true);
  int shapeId = (int)_shapeId.get(drawing); 
  _shapeId.set(drawing, shapeId + 1);

  CTShape shape = CTShape.Factory.newInstance();
  shape.setId("_x0000_s" + shapeId);
  shape.setType("#" + shapeTypeId);
  shape.setFilled(com.microsoft.schemas.vml.STTrueFalse.F);
  shape.setStroked(com.microsoft.schemas.vml.STTrueFalse.F);
  String textboxHTML = 
   "<div style='text-align:left'>"
  +"<font face=\"Tahoma\" size=\"160\" color=\"auto\">" + label + "</font>"
  +"</div>";
  CTTextbox[] textboxArray = new CTTextbox[1];
  textboxArray[0] = CTTextbox.Factory.parse(textboxHTML);
  textboxArray[0].setStyle("mso-direction-alt:auto");
  textboxArray[0].setSingleclick(com.microsoft.schemas.office.office.STTrueFalse.F);
  shape.setTextboxArray(textboxArray);
  CTClientData cldata = shape.addNewClientData();
  cldata.setObjectType(com.microsoft.schemas.office.excel.STObjectType.CHECKBOX);
  cldata.addNewMoveWithCells();
  cldata.addNewSizeWithCells();
  cldata.addNewAnchor().setStringValue(
   "" + col1 + ", " + dx1 + ", " + row1 + ", " +dy1 + ", " + col2 + ", " + dx2 + ", " + row2 + ", " + dy2
  );
  cldata.addAutoFill(com.microsoft.schemas.office.excel.STTrueFalseBlank.FALSE);
  cldata.addAutoLine(com.microsoft.schemas.office.excel.STTrueFalseBlank.FALSE);
  cldata.addTextVAlign("Center");
  cldata.addNoThreeD(com.microsoft.schemas.office.excel.STTrueFalseBlank.TRUE);

  cldata.addChecked((checked)?java.math.BigInteger.valueOf(1):java.math.BigInteger.valueOf(0));

  Field _items = XSSFVMLDrawing.class.getDeclaredField("_items");
  _items.setAccessible(true);
  @SuppressWarnings("unchecked") //we know the problem and expect runtime error if it possibly occurs
  List<XmlObject> items = (List<XmlObject>)_items.get(drawing);

  Field _qnames = XSSFVMLDrawing.class.getDeclaredField("_qnames");
  _qnames.setAccessible(true);
  @SuppressWarnings("unchecked") //we know the problem and expect runtime error if it possibly occurs
  List<QName> qnames = (List<QName>)_qnames.get(drawing);

  items.add(shape);
  qnames.add(new QName("urn:schemas-microsoft-com:vml", "shape"));

 }

 public static void main(String[] args) throws Exception {

  XSSFWorkbook workbook  = new XSSFWorkbook();

  //following is necessary to be textboxHTML of the CTShape compatible with Excel 2007.
  //<fileVersion appName="xl" lastEdited="4" lowestEdited="0" rupBuild="4507"/>
  workbook.getCTWorkbook().addNewFileVersion().setAppName("xl");
  workbook.getCTWorkbook().getFileVersion().setLastEdited("4");
  workbook.getCTWorkbook().getFileVersion().setLowestEdited("0");
  workbook.getCTWorkbook().getFileVersion().setRupBuild("4507");

  XSSFSheet sheet = workbook.createSheet();
  XSSFCell cell = sheet.createRow(5).createCell(5);
/*
  XSSFDrawing drawing = sheet.createDrawingPatriarch();
  XSSFClientAnchor anchor = workbook.getCreationHelper().createClientAnchor();
  anchor.setCol1(cell.getColumnIndex());
  anchor.setCol2(cell.getColumnIndex()+1);
  anchor.setRow1(cell.getRow().getRowNum());
  anchor.setRow2(cell.getRow().getRowNum()+3);
  XSSFComment comment = drawing.createCellComment(anchor);
  XSSFRichTextString str = workbook.getCreationHelper().createRichTextString("Hello, World!");
  comment.setString(str);
  comment.setAuthor("Apache POI");
  cell.setCellComment(comment);
*/
  XSSFVMLDrawing vmlDrawing = getVMLDrawing(sheet);
  addCheckboxShapetype(vmlDrawing);
  addCheckbox(vmlDrawing, 1, 0, 1, 0, 3, 0, 2, 0, "Checkbox 1", true);
  addCheckbox(vmlDrawing, 1, 0, 2, 0, 3, 0, 3, 0, "Checkbox 2", false);

  FileOutputStream out = new FileOutputStream("Excel.xlsx");
  workbook.write(out);
  out.close();
  workbook.close();

 }

}

请注意,对于上述解决方案,如ooxml-schemas-1.4.jar的完整jar(旧版本的较低版本). .html#faq-N10025"rel =" nofollow noreferrer>常见问题解答N10025 .

Please note, for above solution the full jar of all of the schemas ooxml-schemas-1.4.jar (lower versions for older releases) is needed as mentioned in FAQ N10025.

这篇关于使用Apache POI(Java)在XLSX中创建复选框的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆