简体   繁体   中英

Unexplained spacing created in Word Doc table using Apache POI

I'm trying to create a header in a Word Document with the Apache POI library (v5.2.3). I'm using a table so I can get the alignment that I'm looking for. This is the result I'm getting:

在此处输入图像描述

I won't be keeping the table/cell borders, but I've left them in to explain the problem. There's some margin/padding/spacing between the left-most edge of the table and the "Section Title" text, and then similar problem on the right side. I can't figure out what is creating this spacing or how to remove it. I've tried investigating the word doc result in LibreOffice, but I don't understand what element is causing the spacing ie the table, the cells or the paragraph wrapper for the text. The text labels themselves definitely do not contain any extra whitespace characters around them. The phantom indentation does not disappear when the table/cell borders are removed.

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

Here's the output from that logging above:

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]

Those gaps, where the red arrows are pointing to, are not removable. The only thing one can set for a table is a negative left indent and additionally set the table size to be greater than the usable size between left and right page margin. After that, the table hangs at left into the left page margin and at right into the right page margin.

To do so, the page size and the left and right page margins must be known. Additional the table width needs to be set absolute (in TwIps) and not relative in percent.

Example:

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

Nevertheless the exact size of the negative left indent and the oversize of the table can only be got via try and error. And I doubt all word processing applications, which are able to render *.docx , will rendering this the same. So I would not do this and ignore those small gaps. Word processing is word processing and not graphic processing. Means: Word processing is not pixel accurate.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM