Создание флажка в XLSX с использованием Apache POI (Java) - PullRequest
0 голосов
/ 06 ноября 2019

Мне нужно создать флажок Excel в таблице XSSFS, но я не нашел ни очевидных классов / методов для этого в библиотеке Java Apache POI (4.0.1), ни каких-либо примеров. Есть предложения?

1 Ответ

1 голос
/ 13 ноября 2019

В Microsoft Excel возможны два типа элементов управления. Существуют устаревшие элементы управления формой и ActiveX. Создание устаревших элементов управления формы будет возможно. ActiveX элементы управления будут намного сложнее.

Элементы управления прежней формы хранятся в чертежах VML для каждого листа. Apache poi уже имеет класс XSSFVMLDrawing , поскольку комментарии к ячейкам также частично сохраняются в чертежах VML. Но, как часто в apache poi, класс не завершен, и доступность его методов установлена ​​так, что класс не может быть легко расширен. Похоже, что apache poi разработчики часто явно хотят запретить расширение своих классов.

Для устаревших элементов управления Checkbox нам нужен тип формы флажка, а затем формы флажка в этом чертеже VML.

Следующий код создает два устаревших флажка.

Метод XSSFVMLDrawing getVMLDrawing(XSSFSheet sheet) получает чертеж VML с листа или создает новый, если его еще нет.

Метод void addCheckboxShapetype(XSSFVMLDrawing drawing) добавляет новый тип формы флажка для чертежа.

Метод void addCheckbox(XSSFVMLDrawing drawing, int col1, int dx1, int row1, int dy1, int col2, int dx2, int row2, int dy2, String label) добавляет новую фигуру флажка к чертежу, имеющему заданную позицию и метку.

Полный пример:

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) 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);

  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();
  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");
  addCheckbox(vmlDrawing, 1, 0, 2, 0, 3, 0, 3, 0, "Checkbox 2");

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

 }

}
...