java 使用Apache POI在Word文档表中创建的无法解释的间距

brc7rcf0  于 2023-01-29  发布在  Java
关注(0)|答案(1)|浏览(217)

我尝试用Apache POI库(v5.2.3)在Word文档中创建一个标题。我使用了一个表格,这样我就可以得到我想要的对齐方式。这是我得到的结果:

我不会保留表格/单元格边框,但我保留了它们来解释这个问题。在表格的最左边和“节标题”文本之间有一些边距/填充/间距,在右边也有类似的问题。我不知道是什么造成了这个间距,也不知道如何消除它。我试着在LibreOffice中调查word doc结果,但我不明白是什么因素造成了空格,即表格、单元格或文本的段落 Package 。文本标签本身肯定不包含任何额外的空格字符。当表格/单元格边框被删除时,幻影缩进不会消失。

int TWIPS_PER_INCH = 1440;

XWPFHeader header = doc.createHeader(HeaderFooterType.DEFAULT);
XWPFTable table = header.createTable(1, 2);
//table.removeBorders();
table.setWidth("100%");
table.setCellMargins(0, 0, 0, 0);

/*
 * Create CTTblGrid for this table with widths of the 2 columns. 
 * Necessary for Libreoffice/Openoffice to accept the column widths.
 */
table.getCTTbl().addNewTblGrid().addNewGridCol().setW(BigInteger.valueOf(3 * TWIPS_PER_INCH));
table.getCTTbl().getTblGrid().addNewGridCol().setW(BigInteger.valueOf(3 * TWIPS_PER_INCH));

/*
 * Left-Hand Cell
 */
XWPFTableRow tableRow = table.getRow(0);
XWPFTableCell cell = tableRow.getCell(0); 

cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.BOTTOM);
cell.setWidth("50%");

XWPFParagraph paragraph = doc.createParagraph();
paragraph = cell.getParagraphArray(0);
if (paragraph == null) paragraph = cell.addParagraph();

paragraph.setAlignment(ParagraphAlignment.LEFT);
paragraph.setSpacingBefore(0);
paragraph.setSpacingAfter(0);
paragraph.setFirstLineIndent(0);
paragraph.setIndentationLeft(0);

XWPFRun run = paragraph.createRun();
run = paragraph.createRun();
run.setFontFamily("Helvetica");
run.setFontSize(18);
run.setText("Section Title");

/*
 * Right-Hand Cell
 */
cell = tableRow.getCell(1); 
cell.setWidth("50%");
cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.BOTTOM);

paragraph = cell.getParagraphArray(0);
if (paragraph == null) paragraph = cell.addParagraph();

paragraph.setAlignment(ParagraphAlignment.RIGHT);
paragraph.setSpacingBefore(0);
paragraph.setSpacingAfter(0);
paragraph.setFirstLineIndent(0);
paragraph.setIndentationRight(0);

run = paragraph.createRun();
run.setFontFamily("Helvetica");
run.setFontSize(15);
run.setText("Sub-Title");

logger.log( String.format("BOTTOM BORDER SPACE: [%s]\n", table.getBottomBorderSpace()) );
logger.log( String.format("TOP BORDER SPACE: [%s]\n", table.getTopBorderSpace()) );
logger.log( String.format("LEFT BORDER SPACE: [%s]\n", table.getLeftBorderSpace()) );
logger.log( String.format("RIGHT BORDER SPACE: [%s]\n", table.getRightBorderSpace()) );
logger.log( String.format("INSIDE HOR BORDER SPACE: [%s]\n", table.getInsideHBorderSpace()) );
logger.log( String.format("INSIDE VERT BORDER SPACE: [%s]\n", table.getInsideVBorderSpace()) );

logger.log( String.format("BOTTOM CELL MARGIN: [%s]\n", table.getCellMarginBottom()) );
logger.log( String.format("TOP CELL MARGIN: [%s]\n", table.getCellMarginTop()) );
logger.log( String.format("LEFT CELL MARGIN: [%s]\n", table.getCellMarginLeft()) );
logger.log( String.format("RIGHT CELL MARGIN: [%s]\n", table.getCellMarginRight()) );

下面是上述日志记录的输出:

BOTTOM BORDER SPACE: [-1]
TOP BORDER SPACE: [-1]
LEFT BORDER SPACE: [-1]
RIGHT BORDER SPACE: [-1]
INSIDE HOR BORDER SPACE: [-1]
INSIDE VERT BORDER SPACE: [-1]
BOTTOM CELL MARGIN: [0]
TOP CELL MARGIN: [0]
LEFT CELL MARGIN: [0]
RIGHT CELL MARGIN: [0]
fhity93d

fhity93d1#

红色箭头所指的那些间隙是不可删除的。唯一可以为表格设置的是负左缩进,并额外设置表格大小,使其大于左右页边距之间的可用大小。之后,表格将在左侧悬挂到左页边距,在右侧悬挂到右页边距。
为此,页面大小和左右页边距必须已知。另外,表格宽度需要设置为绝对值(以Twips为单位),而不是相对百分比。
示例:

import java.io.*;

import org.apache.poi.xwpf.usermodel.*;
import org.apache.poi.wp.usermodel.HeaderFooterType;

import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;

import java.math.BigInteger;

public class CreateWordHeaderTable {
    
 static void setTableIndent(XWPFTable table, int tblIndW) {
  if (table.getCTTbl().getTblPr() == null) table.getCTTbl().addNewTblPr();  
  if (table.getCTTbl().getTblPr().getTblInd() == null) table.getCTTbl().getTblPr().addNewTblInd();  
  table.getCTTbl().getTblPr().getTblInd().setW(tblIndW);
  table.getCTTbl().getTblPr().getTblInd().setType(org.openxmlformats.schemas.wordprocessingml.x2006.main.STTblWidth.DXA);
 }
 
 static void setDefaultPageSettings(XWPFDocument doc, int pageWidth, int pageHeight, int pageLeftMargin , int pageRightMargin) {
  CTSectPr sectPr = doc.getDocument().getBody().getSectPr();
  if (sectPr == null) sectPr = doc.getDocument().getBody().addNewSectPr();
  CTPageSz pageSz = sectPr.addNewPgSz();
  pageSz.setW(BigInteger.valueOf(pageWidth));
  pageSz.setH(BigInteger.valueOf(pageHeight));
  CTPageMar pageMar = sectPr.getPgMar();
  if (pageMar == null) pageMar = sectPr.addNewPgMar();
  pageMar.setLeft(BigInteger.valueOf(pageLeftMargin)); 
  pageMar.setRight(BigInteger.valueOf(pageRightMargin));
  //pageMar.setTop(BigInteger.valueOf(720)); //720 TWentieths of an Inch Point (Twips) = 720/20 = 36 pt = 36/72 = 0.5"
  //pageMar.setBottom(BigInteger.valueOf(720));
  //pageMar.setFooter(BigInteger.valueOf(720));
  //pageMar.setHeader(BigInteger.valueOf(720));
  //pageMar.setGutter(BigInteger.valueOf(720));
 }

 public static void main(String[] args) throws Exception {
     
  int TWIPS_PER_INCH = 1440;
  
  try (
   XWPFDocument doc = new XWPFDocument();
   FileOutputStream out = new FileOutputStream("./CreateWordHeaderTable.docx");
   ) {
       
   int pageWidth = (int)Math.round(8.5 * TWIPS_PER_INCH); // page size letter
   int pageHeight = (int)Math.round(11 * TWIPS_PER_INCH); // page size letter
   int pageLeftMargin = (int)Math.round(1 * TWIPS_PER_INCH);
   int pageRightMargin = (int)Math.round(1 * TWIPS_PER_INCH);

   setDefaultPageSettings(doc, pageWidth, pageHeight, pageLeftMargin, pageRightMargin);
   
   // the body content
   XWPFParagraph paragraph = doc.createParagraph();
   XWPFRun run = paragraph.createRun();  
   run.setText("The Body... lorem ipsum...");

   // create header
   XWPFHeader header = doc.createHeader(HeaderFooterType.DEFAULT);
   XWPFTable table = header.createTable(1, 2);
   //table.removeBorders();
   table.setCellMargins(0, 0, 0, 0);
   
   int leftTableIndent = (int)Math.round(-0.025 * TWIPS_PER_INCH);
   setTableIndent(table, leftTableIndent);
   //table.setWidth("100%");
   int tableOversize = (int)Math.round(0.15 * TWIPS_PER_INCH);
   int tableWidth = pageWidth - pageLeftMargin - pageRightMargin + tableOversize;
   table.setWidth(tableWidth);
   
   /*
    * Create CTTblGrid for this table with widths of the 2 columns. 
    * Necessary for Libreoffice/Openoffice to accept the column widths.
    */
   table.getCTTbl().addNewTblGrid().addNewGridCol().setW(BigInteger.valueOf(1 * TWIPS_PER_INCH));
   table.getCTTbl().getTblGrid().addNewGridCol().setW(BigInteger.valueOf(1 * TWIPS_PER_INCH));
  
   /*
    * Left-Hand Cell
    */
   XWPFTableRow tableRow = table.getRow(0);
   XWPFTableCell cell = tableRow.getCell(0); 

   cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.BOTTOM);
   cell.setWidth("50%");

   paragraph = doc.createParagraph();
   paragraph = cell.getParagraphArray(0);
   if (paragraph == null) paragraph = cell.addParagraph();

   paragraph.setAlignment(ParagraphAlignment.LEFT);
   run = paragraph.createRun();
   run = paragraph.createRun();
   run.setFontFamily("Helvetica");
   run.setFontSize(18);
   run.setText("Section Title");

   /*
    * Right-Hand Cell
    */
   cell = tableRow.getCell(1); 
   cell.setWidth("50%");
   cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.BOTTOM);

   paragraph = cell.getParagraphArray(0);
   if (paragraph == null) paragraph = cell.addParagraph();

   paragraph.setAlignment(ParagraphAlignment.RIGHT);
   run = paragraph.createRun();
   run.setFontFamily("Helvetica");
   run.setFontSize(15);
   run.setText("Sub-Title");

   paragraph = header.createParagraph();
   paragraph.setAlignment(ParagraphAlignment.LEFT);
   run = paragraph.createRun();
   run.setText("|...Next Line in Header...|");
  
   doc.write(out);
   
  }
 }
}

尽管如此,负左缩进的确切大小和表的过大尺寸只能通过尝试和错误来获得。我怀疑所有能够渲染*.docx的字处理应用程序都能渲染出相同的结果。所以我不会这样做,也不会忽略那些小的差距。字处理是字处理,而不是图形处理。意思是:文字处理不是像素精确的。

相关问题