I have problem with vertical merging cells if there is multiple merging in same row. For example : I want to merge row(0).getCell(0) with row(1).getCell(0) and row(0).getCell(1) with row(1).getCell(1) its merge only second.
Method which I use
private void mergeCellsV(XWPFTableCell cellStart, XWPFTableCell cellFinish) {
cellStart.getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.RESTART);
cellFinish.getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.CONTINUE);
}
XWPFTableRow row0 = tablePK.getRow(0);
XWPFTableRow row1 = tablePK.getRow(1);
XWPFTableRow row2 = tablePK.getRow(2);
XWPFTableRow row3 = tablePK.getRow(3);
mergeCellsV(row0.getCell(0), row1.getCell(0));
mergeCellsV(row0.getCell(1), row1.getCell(1));
mergeCellsV(row0.getCell(5), row1.getCell(5));
mergeCellsV(row0.getCell(6), row1.getCell(6));
mergeCellsV(row2.getCell(0), row3.getCell(0));
mergeCellsV(row2.getCell(1), row3.getCell(1));
mergeCellsV(row2.getCell(5), row3.getCell(5));
mergeCellsV(row2.getCell(6), row3.getCell(6));
Result :
adding just one merge and works fine mergeCellsV(row2.getCell(6), row3.getCell(6));
The main question while merging table cells, aside the question what merging settings to use as there are multiple possible settings and as there are compatibility issues between different word processing applications, is: What about the cells which get merged? For example if you merge horizontally cell 3 and 4 in a table row having 6 cells, then after that that row only contains 5 cells. And if you then need merging vertically formerly cell 5 of that row with cell 5 of row below, then this will fail, because formerly cell 5 now is cell 4.
Thats why best practice for merging is following:
Following complete code shows this for the example you seems want to create:
import java.io.FileOutputStream;
import java.math.BigInteger;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.poi.xwpf.usermodel.ParagraphAlignment;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTcPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTVMerge;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STMerge;
public class CreateWordTableMergeTest {
static final String FONT_FAMILY = "Calibri";
static final int FONT_SIZE = 10;
static void mergeCellVertically(XWPFTable table, int col, int fromRow, int toRow) {
for(int rowIndex = fromRow; rowIndex <= toRow; rowIndex++) {
XWPFTableCell cell = table.getRow(rowIndex).getCell(col);
CTVMerge vmerge = CTVMerge.Factory.newInstance();
if(rowIndex == fromRow){
// The first merged cell is set with RESTART merge value
vmerge.setVal(STMerge.RESTART);
} else {
// Cells which join (merge) the first one, are set with CONTINUE
vmerge.setVal(STMerge.CONTINUE);
// and the content should be removed
for (int i = cell.getParagraphs().size(); i > 0; i--) {
cell.removeParagraph(0);
}
cell.addParagraph();
}
// Try getting the TcPr. Not simply setting an new one every time.
CTTcPr tcPr = cell.getCTTc().getTcPr();
if (tcPr == null) tcPr = cell.getCTTc().addNewTcPr();
tcPr.setVMerge(vmerge);
}
}
//merging horizontally by setting grid span instead of using CTHMerge
static void mergeCellHorizontally(XWPFTable table, int row, int fromCol, int toCol) {
XWPFTableCell cell = table.getRow(row).getCell(fromCol);
// Try getting the TcPr. Not simply setting an new one every time.
CTTcPr tcPr = cell.getCTTc().getTcPr();
if (tcPr == null) tcPr = cell.getCTTc().addNewTcPr();
// The first merged cell has grid span property set
if (tcPr.isSetGridSpan()) {
tcPr.getGridSpan().setVal(BigInteger.valueOf(toCol-fromCol+1));
} else {
tcPr.addNewGridSpan().setVal(BigInteger.valueOf(toCol-fromCol+1));
}
// Cells which join (merge) the first one, must be removed
for(int colIndex = toCol; colIndex > fromCol; colIndex--) {
//table.getRow(row).removeCell(colIndex); // use only this for apache poi versions greater than 4.1.1
table.getRow(row).getCtRow().removeTc(colIndex); // use this for apache poi versions up to 4.1.1
table.getRow(row).removeCell(colIndex);
}
}
static void createFormattedTableCell(XWPFTableCell cell, String text, String fontFamily, int fontSize, ParagraphAlignment align) {
XWPFParagraph paragraph = cell.getParagraphArray(0);
if (paragraph == null) {
paragraph = cell.addParagraph();
}
paragraph.setIndentationFirstLine(0);
paragraph.setIndentationLeft(0);
XWPFRun run = paragraph.createRun();
run.setFontFamily(fontFamily);
run.setFontSize(fontSize);
String[] lines = text.split("\n");
if (lines.length > 1) {
run.setText(lines[0], 0);
for (int i = 1; i < lines.length; i++) {
XWPFParagraph pnew = cell.addParagraph();
cell.addParagraph(pnew);
pnew.setSpacingAfter(0);
pnew.setSpacingBefore(0);
XWPFRun run2 = pnew.createRun();
run2.setText(lines[i], 0);
run2.setFontFamily(fontFamily);
run2.setFontSize(fontSize);
pnew.setAlignment(align);
}
} else {
run.setText(text);
}
paragraph.setAlignment(align);
paragraph.setSpacingBeforeLines(1);
paragraph.setSpacingAfterLines(1);
paragraph.setSpacingBefore(1);
paragraph.setSpacingAfter(1);
cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);
}
public static void main(String[] args) throws Exception {
XWPFDocument document= new XWPFDocument();
XWPFParagraph paragraph = document.createParagraph();
XWPFRun run=paragraph.createRun();
run.setText("The table:");
//create table
XWPFTable table = document.createTable();
table.setCellMargins(20, 0, 20, 0);
//styleTable(table, "100%", ParagraphAlignment.CENTER);
table.setWidth("100%");
//create CTTblGrid for this table with widths of the 7 columns.
//necessary for Libreoffice/Openoffice to accept the column widths.
//values are in unit twentieths of a point (1/1440 of an inch)
//first column = 1 inches width
table.getCTTbl().addNewTblGrid().addNewGridCol().setW(BigInteger.valueOf(1*1440));
//other columns (6 in this case) also each 1 inches width
for (int col = 1 ; col < 7; col++) {
table.getCTTbl().getTblGrid().addNewGridCol().setW(BigInteger.valueOf(1*1440));
}
//add table content
XWPFTableRow tableRow = table.getRow(0);
int numCells = 7;
for (int i = 0; i < numCells; i++) {
XWPFTableCell tableCell = tableRow.getCell(i);
if (tableCell == null) {
tableCell = tableRow.addNewTableCell();
tableCell.setWidth("16.66%");
}
}
createFormattedTableCell(tableRow.getCell(0), "PAKOVANJE / UNIT", FONT_FAMILY, FONT_SIZE, ParagraphAlignment.LEFT);
createFormattedTableCell(tableRow.getCell(2), "DIMENZIJE / DIMENSIONS", FONT_FAMILY, FONT_SIZE, ParagraphAlignment.CENTER);
createFormattedTableCell(tableRow.getCell(5), "NETO", FONT_FAMILY, FONT_SIZE, ParagraphAlignment.CENTER);
createFormattedTableCell(tableRow.getCell(6), "BRUTO", FONT_FAMILY, FONT_SIZE, ParagraphAlignment.CENTER);
//mergeCellsH(tableRow.getCell(3), tableRow.getCell(5)); //this working fine - may be, but I doubt that
table.createRow();
tableRow = table.getRow(1);
numCells = 7;
for (int i = 0; i < numCells; i++) {
XWPFTableCell tableCell = tableRow.getCell(i);
if (tableCell == null) {
tableCell = tableRow.addNewTableCell();
}
}
createFormattedTableCell(tableRow.getCell(2), "Širina/Width", FONT_FAMILY, FONT_SIZE, ParagraphAlignment.CENTER);
createFormattedTableCell(tableRow.getCell(3), "Dubina/Depth", FONT_FAMILY, FONT_SIZE, ParagraphAlignment.CENTER);
createFormattedTableCell(tableRow.getCell(4), "Visina/Heigth", FONT_FAMILY, FONT_SIZE, ParagraphAlignment.CENTER);
table.createRow();
tableRow = table.getRow(2);
numCells = 7;
for (int i = 0; i < numCells; i++) {
XWPFTableCell tableCell = tableRow.getCell(i);
if (tableCell == null) {
tableCell = tableRow.addNewTableCell();
}
}
createFormattedTableCell(tableRow.getCell(0), "POJEDINAČNO / CONSUMER", FONT_FAMILY, FONT_SIZE, ParagraphAlignment.LEFT);
createFormattedTableCell(tableRow.getCell(2), "NAZIV AMBALAŽA", FONT_FAMILY, FONT_SIZE, ParagraphAlignment.CENTER);
createFormattedTableCell(tableRow.getCell(5), "14", FONT_FAMILY, FONT_SIZE, ParagraphAlignment.CENTER);
createFormattedTableCell(tableRow.getCell(6), "15", FONT_FAMILY, FONT_SIZE, ParagraphAlignment.CENTER);
table.createRow();
tableRow = table.getRow(3);
numCells = 7;
for (int i = 0; i < numCells; i++) {
XWPFTableCell tableCell = tableRow.getCell(i);
if (tableCell == null) {
tableCell = tableRow.addNewTableCell();
}
}
createFormattedTableCell(tableRow.getCell(2), "11", FONT_FAMILY, FONT_SIZE, ParagraphAlignment.CENTER);
createFormattedTableCell(tableRow.getCell(3), "12", FONT_FAMILY, FONT_SIZE, ParagraphAlignment.CENTER);
createFormattedTableCell(tableRow.getCell(4), "13", FONT_FAMILY, FONT_SIZE, ParagraphAlignment.CENTER);
//merging cells
mergeCellVertically(table, 0, 0, 1);
mergeCellVertically(table, 1, 0, 1);
mergeCellVertically(table, 5, 0, 1);
mergeCellVertically(table, 6, 0, 1);
mergeCellVertically(table, 0, 2, 3);
mergeCellVertically(table, 1, 2, 3);
mergeCellVertically(table, 5, 2, 3);
mergeCellVertically(table, 6, 2, 3);
mergeCellHorizontally(table, 0, 2, 4);
mergeCellHorizontally(table, 2, 2, 4);
paragraph = document.createParagraph();
FileOutputStream out = new FileOutputStream("./create_table.docx");
document.write(out);
out.close();
document.close();
}
}
Above code is tested using Apache POI version 4.1.1. It produces: