Set columnwidth of a table in XWPFTableCell (docx)
Asked Answered
M

5

15

I'm generating a docx file with apache-poi. In the wordfile, I add tables, whose columns have a width I would like to see fixed.

Currently, I use the technique described here: http://apache-poi.1045710.n5.nabble.com/Is-there-a-way-to-set-the-width-of-a-column-in-XWPFTableCell-td5711491.html

Basically, this entails setting

cell.getCTTc().addNewTcPr().addNewTcW().setW(BigInteger.valueOf(cols[j])); 

on each cell of that column.

The problem is that while the file opens perfectly in MS Word, open office interprets the values I set to the columnwidth differently. Whereas MS Word apparantly assumes 20-th of a point as units, open office seems to use points instead and therefore all columns are 20 times wider when I open the generated document in OO.

Usually when I see something weird in the generated output, I unpack the docx file, see what the value should be and change my code. But open office does not seem to be able to save to docx, so I can't change the value in OO save it back and see if Word still interprets the document correctly in order to find a cross-application solution.

Any idea how I set the width of the table column so that both OO and MS Wordt interprets it the same?

Marchland answered 18/11, 2013 at 10:51 Comment(0)
W
16

Don't touch single cells. Add a GRID:

XWPFDocument doc = new XWPFDocument();
XWPFTable table = doc.createTable(1,2);
table.getCTTbl().addNewTblGrid().addNewGridCol().setW(BigInteger.valueOf(6000));
table.getCTTbl().getTblGrid().addNewGridCol().setW(BigInteger.valueOf(2000));
table.getRow(0).getCell(0).setText("1A");
table.getRow(0).getCell(1).setText("1B");
XWPFTableRow newrow = table.createRow();
newrow.getCell(0).setText("2A");
newrow.getCell(1).setText("2B");

The grid sets widths for entire columns. You don't need to do any cycles to set a width for every cell. It works in LibreOffice and GoogleDocs.

To watch the seted width in MS Word too, you may set widths of cells in the first row:

 widthCellsAcrossRow(table, 0, 0, 4000);
 widthCellsAcrossRow(table, 0, 0, 5000);

private static void widthCellsAcrossRow (XWPFTable table, int rowNum, int colNum, int width) {
        XWPFTableCell cell = table.getRow(rowNum).getCell(colNum);
        if (cell.getCTTc().getTcPr() == null)
            cell.getCTTc().addNewTcPr();
        if (cell.getCTTc().getTcPr().getTcW()==null)
            cell.getCTTc().getTcPr().addNewTcW();
        cell.getCTTc().getTcPr().getTcW().setW(BigInteger.valueOf((long) width));
}
Weiman answered 3/3, 2016 at 6:34 Comment(1)
This works properly .... if you also set the table layout to "fixed" - see comment above.Superheterodyne
E
11

Answer extracted from question:

It was recently pointed out to me that LibreOffice is able to save to docx. By changing the generated file and saving it back and decompiling the result, I have been able to resolve the issue.

Key is to put an explicit width to the table itself first. Word doesn't seem to care about its presence, and OpenOffice/LibreOffice are able to render the table correctly.

So, after creation of the table, I did as follows:

CTTblWidth width = table.getCTTbl().addNewTblPr().addNewTblW();
width.setType(STTblWidth.DXA);
width.setW(BigInteger.valueOf(9072));
Existentialism answered 18/11, 2013 at 10:51 Comment(0)
P
6

Upon creation of the table, the layout is set to "auto" by default hence the width of the cell will always increase to follow the length of the string. As per OpenXML markup, it look's like w:tblPr w:tblLayout w:type="auto"
the solution is to set the layout to fixed and set the individual column length w:tblPr w:tblLayout w:type="fixed"

Here's the poi code for setting table layout:

XWPFTable table = document.createTable();
CTTblLayoutType type = table.getCTTbl().getTblPr().addNewTblLayout();
type.setType(STTblLayoutType.FIXED);

Here's how to set the individual width:

 int[] cols = {
    4896,
    1872,
    4032,
    1728,
    1440
};

for (int i = 0; i < table.getNumberOfRows(); i++) {
    XWPFTableRow row = table.getRow(i);
    int numCells = row.getTableCells().size();
    for (int j = 0; j < numCells; j++) {
        XWPFTableCell cell = row.getCell(j);
        CTTblWidth cellWidth = cell.getCTTc().addNewTcPr().addNewTcW();
        CTTcPr pr = cell.getCTTc().addNewTcPr();
        pr.addNewNoWrap();
        cellWidth.setW(BigInteger.valueOf(cols[j]));
    }
}

column lengths are in twentieths of a point (dxa) or 1/1440 inch.

Pismire answered 21/12, 2016 at 8:40 Comment(1)
THAT was the key! Setting the table layout to fixed. Thank you. I had id all ... set a grid layout for the table, set the cell sizes properly ... but had not set the table layout. Works now for me.Superheterodyne
H
0

This is a major and very tricky element. I solved it using this own generic method of setting the widths of a table cell.

private static void setTableColumnWidths(XWPFTable table) {
    table.getCTTbl().addNewTblGrid().addNewGridCol().setW(BigInteger.valueOf(2000));
    table.getCTTbl().getTblGrid().addNewGridCol().setW(BigInteger.valueOf(3200));
    table.getCTTbl().getTblGrid().addNewGridCol().setW(BigInteger.valueOf(1000));
    table.getCTTbl().getTblGrid().addNewGridCol().setW(BigInteger.valueOf(1000));
    table.getCTTbl().getTblGrid().addNewGridCol().setW(BigInteger.valueOf(1105));
    table.getCTTbl().getTblGrid().addNewGridCol().setW(BigInteger.valueOf(1105));
}
Hectometer answered 20/6, 2017 at 10:2 Comment(3)
Hey Rahul. Please don't do this begging for "please upvote". If you post good answers (this one isn't good), you'll get your merits automatically, but please don't beg all of the time.Ludivinaludlew
Alexander (this one isn't good). ok i will take your suggestion but please do not put your nose. this is place for sharing the knowledge not the arguments.Hectometer
I wouldn't call the method "generic". :P Its pretty much as ad hoc as can be.Jutta
P
0

Based on other answers...

  public static void setTableColumnsWidth(XWPFTable table, long... widths) {
    CTTblGrid grid = table.getCTTbl().addNewTblGrid();
    for (long w : widths) {
      grid.addNewGridCol().setW(BigInteger.valueOf(w));
    }    
  }

Usage:

setTableColumnsWidth(table, 1440, 2700, 3000, 1440);
Pentavalent answered 27/4, 2019 at 19:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.