为ppt表格XSLFTable创建新行而不丢失单元格样式

问题描述 投票:0回答:1

我正在尝试使用 apache poi 在 powerpoint 幻灯片中的现有示例表中创建新行而不丢失格式,但仍然无法获取它。

enter image description here

我希望添加一行时会有一个与上一行具有相同样式的新行,但是并没有保持样式。

enter image description here

我试图这样做,但我不能,因为不可能有 XSLFTable 的实例。尝试在另一个主题中搜索答案,但其他场景与允许保持风格的 XSFTable 相关。

            XSLFTableRow oldRow = table.getRows().get(1);
            CTRow ctrow = CTRow.Factory.parse(oldRow.getXmlObject().newInputStream());
            XSLFTableRow newRow = new XSLFTableRow(ctrow, table); //Not possible to do this for ppt table

            XSLFTableCell cell = newRow.addCell();
            XSLFTextParagraph paragraph = cell.addNewTextParagraph();
            XSLFTextRun textRun = paragraph.addNewTextRun();
            textRun.setText("User 2");

感谢您的帮助。

java apache-poi
1个回答
0
投票

文本表格,例如 Word 表格和 PowerPoint 表格,确实是野兽。 Apache POI 开发人员做出了非常不同的、有时令人难以理解的决定来处理这些野兽。

对于 PowerPoint 表格,可以使用 XSLFTable.addRow 向当前表格添加新行。但这只会添加一个具有默认高度的新空行,请参阅XSLFTable.java

要获得上一行的完整副本,可以调用 XSLFTableRow 构造函数

XSLFTableRow(CTTableRow row, XSLFTable table)
拥有
CTTableRow row
上一个表行的
CTTableRow
的完整副本。但该构造函数不是公共的,而是仅在内部打包。为什么?我不知道。

幸运的是,如果某些东西不是公开的,Java 中有反射来获取它。

因此,我们可以像

XSLFTable.addRow
那样使用
CTTableRow row
做前一个表行
CTTableRow
的完整副本。

之后,我们有一个新的表行,它是前一个表行的精确副本。

完整示例:

import java.io.FileInputStream;
import java.io.FileOutputStream;

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

public class PPTXAddTableRow {
    
 static XSLFTableRow addTableRow(XSLFTable table) throws Exception {
  XSLFTableRow lastRow = table.getRows().get(table.getNumberOfRows()-1);
  org.openxmlformats.schemas.drawingml.x2006.main.CTTableRow ctTableRowLastRow = lastRow.getXmlObject();
  
  java.lang.reflect.Field __table = XSLFTable.class.getDeclaredField("_table");
  __table.setAccessible(true);
  org.openxmlformats.schemas.drawingml.x2006.main.CTTable _table = (org.openxmlformats.schemas.drawingml.x2006.main.CTTable)__table.get(table);
  org.openxmlformats.schemas.drawingml.x2006.main.CTTableRow ctTableRowNew = _table.addNewTr();
  ctTableRowNew.set(ctTableRowLastRow.copy());
  
  java.lang.reflect.Constructor constructor = XSLFTableRow.class.getDeclaredConstructor(org.openxmlformats.schemas.drawingml.x2006.main.CTTableRow.class, XSLFTable.class);
  constructor.setAccessible(true);
  XSLFTableRow newRow = (XSLFTableRow)constructor.newInstance(ctTableRowNew, table);
  
  java.lang.reflect.Field __rows = XSLFTable.class.getDeclaredField("_rows");
  __rows.setAccessible(true);
  @SuppressWarnings("unchecked")
  java.util.List<XSLFTableRow> _rows = (java.util.List<XSLFTableRow>)__rows.get(table);
  _rows.add(newRow);
  
  java.lang.reflect.Method updateRowColIndexes = XSLFTable.class.getDeclaredMethod("updateRowColIndexes");
  updateRowColIndexes.setAccessible(true);
  updateRowColIndexes.invoke(table);  
  
  return newRow;  
 }
     
 public static void main(String[] args) throws Exception {

  XMLSlideShow slideShow = new XMLSlideShow(new FileInputStream("./TableSample.pptx"));
  
  for (XSLFSlide slide : slideShow.getSlides()) {
   for (XSLFShape shape : slide.getShapes()) {
    if (shape instanceof XSLFTable) {
     XSLFTable table = (XSLFTable)shape;
     XSLFTableRow newTableRow = addTableRow(table);
     for (XSLFTableCell cell : newTableRow.getCells()) {
      cell.setText("new text");
     }       
    }       
   }      
  }
    
  FileOutputStream out = new FileOutputStream("./TableSampleNew.pptx");
  slideShow.write(out);
  out.close();
  slideShow.close();
 }
}

注意这里使用

XSLFTableCell.setText
是为了简化。但这会丢失可能的文本段落和文本运行格式。因此,可能需要使用
XSLFTableCell
-
XSLFTextShape
的文本段落和文本运行,而不是
XSLFTableCell.setText

© www.soinside.com 2019 - 2024. All rights reserved.