Правильное изображение введите здесь описание изображения
Таблицы не объединены в таблицу.
Обычные таблицы хорошо объединяются.
Интересно, в чем причина.
public static void main(String[] args) {
try {
XWPFDocument doc = new XWPFDocument();
// create main table
XWPFTable table = doc.createTable();
// create rows and cells
XWPFTableRow row = table.getRow(0);
row.getCell(0).setText("Main table A1");
row.addNewTableCell().setText("Main table B1");
row.addNewTableCell().setText("Main table C1");
row = table.createRow();
row.setHeight(2000);
row.getCell(0).setText("Main table A2");
row.getCell(1).setText("Main table B2");
row.getCell(2).setText("Main table C2");
row = table.createRow();
row.setHeight(2000);
row.getCell(0).setText("Main table d2");
row.getCell(1).setText("Main table d2");
row.getCell(2).setText("Main table d2");
// 1
row = table.getRow(0);
XWPFTableCell cell = row.getTableCells().get(0);
XWPFParagraph paragraph = cell.addParagraph();
// 2
org.apache.xmlbeans.XmlCursor cursor = paragraph.getCTP().newCursor();
XWPFTable innerTable = cell.insertNewTbl(cursor);
// 3
innerTable.setTopBorder(XWPFTable.XWPFBorderType.SINGLE, 4, 0, "000000");
innerTable.setRightBorder(XWPFTable.XWPFBorderType.SINGLE, 4, 0, "000000");
innerTable.setBottomBorder(XWPFTable.XWPFBorderType.SINGLE, 4, 0, "000000");
innerTable.setLeftBorder(XWPFTable.XWPFBorderType.SINGLE, 4, 0, "000000");
innerTable.setInsideHBorder(XWPFTable.XWPFBorderType.SINGLE, 4, 0, "000000");
innerTable.setInsideVBorder(XWPFTable.XWPFBorderType.SINGLE, 4, 0, "000000");
// 4
XWPFTableRow rowInInnerTable = innerTable.createRow();
rowInInnerTable.setHeight(1000);
XWPFTableCell cellInInnerTable = rowInInnerTable.createCell();
cellInInnerTable.setColor("FF00FF");
rowInInnerTable.getCell(0).setWidth("700");
rowInInnerTable.getCell(0).setVerticalAlignment(XWPFVertAlign.CENTER);
XWPFParagraph p5 = rowInInnerTable.getCell(0).getParagraphs().get(0);
p5.setAlignment(ParagraphAlignment.CENTER);
XWPFRun r5 = p5.createRun();
r5.setFontSize(10);
r5.setText("SUB_TAB1");
cellInInnerTable = rowInInnerTable.createCell();
rowInInnerTable.getCell(1).setWidth("300"); // ??? ??
rowInInnerTable.getCell(1).setVerticalAlignment(XWPFVertAlign.CENTER);
cellInInnerTable.setColor("FF00FF"); // ??
p5 = rowInInnerTable.getCell(1).getParagraphs().get(0);
p5.setAlignment(ParagraphAlignment.CENTER);
r5 = p5.createRun();
r5.setFontSize(10);
r5.setText("SUB_TAB3");
cellInInnerTable = rowInInnerTable.createCell();
cellInInnerTable.setColor("FF00FF"); // ??
rowInInnerTable.getCell(2).setWidth("2000"); // ??? ??
rowInInnerTable.getCell(2).setVerticalAlignment(XWPFVertAlign.CENTER);
p5 = rowInInnerTable.getCell(2).getParagraphs().get(0);
p5.setAlignment(ParagraphAlignment.CENTER);
r5 = p5.createRun();
r5.setText("SUB_TAB4");
rowInInnerTable = innerTable.createRow();
cellInInnerTable = rowInInnerTable.getCell(0);
p5 = rowInInnerTable.getCell(0).getParagraphs().get(0);
p5.setAlignment(ParagraphAlignment.CENTER);
r5 = p5.createRun();
r5.setText("AA");
cellInInnerTable = rowInInnerTable.getCell(1);
p5 = rowInInnerTable.getCell(1).getParagraphs().get(0);
p5.setAlignment(ParagraphAlignment.CENTER);
r5 = p5.createRun();
r5.setText("BB1");
cellInInnerTable = rowInInnerTable.getCell(2);
p5 = rowInInnerTable.getCell(2).getParagraphs().get(0);
p5.setAlignment(ParagraphAlignment.CENTER);
r5 = p5.createRun();
r5.setText("CC");
rowInInnerTable = innerTable.createRow();
cellInInnerTable = rowInInnerTable.getCell(0);
p5 = rowInInnerTable.getCell(0).getParagraphs().get(0);
p5.setAlignment(ParagraphAlignment.CENTER);
r5 = p5.createRun();
r5.setText("AA_2");
setColumnWidth(table, 0, 0, 4500);
setColumnWidth(table, 0, 1, 2000);
setColumnWidth(table, 0, 2, 2000);
mergeCellVertically(table, 1, 1, 2);
mergeCellVertically(innerTable, 1, 1, 2); // ????????????????????????????
// save to .docx file
try (FileOutputStream out = new FileOutputStream("c:\\test\\MAIN_table.docx")) {
doc.write(out);
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void setColumnWidth(XWPFTable table, int row, int col, int width) {
CTTblWidth tblWidth = CTTblWidth.Factory.newInstance();
tblWidth.setW(BigInteger.valueOf(width));
tblWidth.setType(STTblWidth.DXA);
CTTcPr tcPr = table.getRow(row).getCell(col).getCTTc().getTcPr();
if (tcPr != null) {
tcPr.setTcW(tblWidth);
} else {
tcPr = CTTcPr.Factory.newInstance();
tcPr.setTcW(tblWidth);
table.getRow(row).getCell(col).getCTTc().setTcPr(tcPr);
}
}
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) {
vmerge.setVal(STMerge.RESTART);
} else {
vmerge.setVal(STMerge.CONTINUE);
for (int i = cell.getParagraphs().size(); i > 0; i--) {
cell.removeParagraph(0);
}
cell.addParagraph();
}
CTTcPr tcPr = cell.getCTTc().getTcPr();
if (tcPr == null) {
tcPr = cell.getCTTc().addNewTcPr();
}
tcPr.setVMerge(vmerge);
}
}
гм, простите меня, но я не совсем понимаю, какую часть следует объединять, а какую нет. на картинке изображен ожидаемый результат или проблема?
Второй и третий должны слиться.
Кажется, что XWPFTable.createRow искажает массив строк таблицы, по крайней мере, для таблиц в таблицах. Моя отладка показала, что XWPFTable.getRow(0)
получает вторую строку, когда XWPFTable
является таблицей в таблице, а строка была добавлена с помощью XWPFTable.createRow
. Тогда XWPFTable.getRow(1)
получает третью строку, а первая строка недостижима с помощью XWPFTable.getRow
.
Если для добавления строк используется XWPFTable.insertNewTableRow, то XWPFTable.getRow
работает корректно.
Полный пример:
import java.io.*;
import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
public class CreateWordTableInTable2 {
public static void main(String[] args) {
try {
XWPFDocument doc = new XWPFDocument();
// create main table
XWPFTable table = doc.createTable();
// create rows and cells
XWPFTableRow row = table.getRow(0);
row.getCell(0).setText("Main table A1");
row.addNewTableCell().setText("Main table B1");
row.addNewTableCell().setText("Main table C1");
row = table.createRow();
row.setHeight(2000);
row.getCell(0).setText("Main table A2");
row.getCell(1).setText("Main table B2");
row.getCell(2).setText("Main table C2");
row = table.createRow();
row.setHeight(2000);
row.getCell(0).setText("Main table d2");
row.getCell(1).setText("Main table d2");
row.getCell(2).setText("Main table d2");
// 1
row = table.getRow(0);
XWPFTableCell cell = row.getTableCells().get(0);
XWPFParagraph paragraph = cell.addParagraph();
// 2
org.apache.xmlbeans.XmlCursor cursor = paragraph.getCTP().newCursor();
XWPFTable innerTable = cell.insertNewTbl(cursor);
// 3
innerTable.setTopBorder(XWPFTable.XWPFBorderType.SINGLE, 4, 0, "000000");
innerTable.setRightBorder(XWPFTable.XWPFBorderType.SINGLE, 4, 0, "000000");
innerTable.setBottomBorder(XWPFTable.XWPFBorderType.SINGLE, 4, 0, "000000");
innerTable.setLeftBorder(XWPFTable.XWPFBorderType.SINGLE, 4, 0, "000000");
innerTable.setInsideHBorder(XWPFTable.XWPFBorderType.SINGLE, 4, 0, "000000");
innerTable.setInsideVBorder(XWPFTable.XWPFBorderType.SINGLE, 4, 0, "000000");
// 4
//XWPFTableRow rowInInnerTable = innerTable.createRow();
XWPFTableRow rowInInnerTable = innerTable.insertNewTableRow(0);
rowInInnerTable.setHeight(1000);
XWPFTableCell cellInInnerTable = rowInInnerTable.createCell();
cellInInnerTable.setColor("FF00FF");
rowInInnerTable.getCell(0).setWidth("700");
rowInInnerTable.getCell(0).setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);
XWPFParagraph p5 = rowInInnerTable.getCell(0).getParagraphs().get(0);
p5.setAlignment(ParagraphAlignment.CENTER);
XWPFRun r5 = p5.createRun();
r5.setFontSize(10);
r5.setText("SUB_TAB1");
cellInInnerTable = rowInInnerTable.createCell();
rowInInnerTable.getCell(1).setWidth("300"); // ??? ??
rowInInnerTable.getCell(1).setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);
cellInInnerTable.setColor("FF00FF"); // ??
p5 = rowInInnerTable.getCell(1).getParagraphs().get(0);
p5.setAlignment(ParagraphAlignment.CENTER);
r5 = p5.createRun();
r5.setFontSize(10);
r5.setText("SUB_TAB3");
cellInInnerTable = rowInInnerTable.createCell();
cellInInnerTable.setColor("FF00FF"); // ??
rowInInnerTable.getCell(2).setWidth("2000"); // ??? ??
rowInInnerTable.getCell(2).setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);
p5 = rowInInnerTable.getCell(2).getParagraphs().get(0);
p5.setAlignment(ParagraphAlignment.CENTER);
r5 = p5.createRun();
r5.setText("SUB_TAB4");
//rowInInnerTable = innerTable.createRow();
//cellInInnerTable = rowInInnerTable.getCell(0);
rowInInnerTable = innerTable.insertNewTableRow(1);
cellInInnerTable = rowInInnerTable.createCell();
p5 = rowInInnerTable.getCell(0).getParagraphs().get(0);
p5.setAlignment(ParagraphAlignment.CENTER);
r5 = p5.createRun();
r5.setText("AA");
//cellInInnerTable = rowInInnerTable.getCell(1);
cellInInnerTable = rowInInnerTable.createCell();
p5 = rowInInnerTable.getCell(1).getParagraphs().get(0);
p5.setAlignment(ParagraphAlignment.CENTER);
r5 = p5.createRun();
r5.setText("BB1");
//cellInInnerTable = rowInInnerTable.getCell(2);
cellInInnerTable = rowInInnerTable.createCell();
p5 = rowInInnerTable.getCell(2).getParagraphs().get(0);
p5.setAlignment(ParagraphAlignment.CENTER);
r5 = p5.createRun();
r5.setText("CC");
//rowInInnerTable = innerTable.createRow();
//cellInInnerTable = rowInInnerTable.getCell(0);
rowInInnerTable = innerTable.insertNewTableRow(2);
cellInInnerTable = rowInInnerTable.createCell();
p5 = rowInInnerTable.getCell(0).getParagraphs().get(0);
p5.setAlignment(ParagraphAlignment.CENTER);
r5 = p5.createRun();
r5.setText("AA_2");
//cellInInnerTable = rowInInnerTable.getCell(1);
cellInInnerTable = rowInInnerTable.createCell();
//cellInInnerTable = rowInInnerTable.getCell(2);
cellInInnerTable = rowInInnerTable.createCell();
setColumnWidth(table, 0, 0, 4500);
setColumnWidth(table, 0, 1, 2000);
setColumnWidth(table, 0, 2, 2000);
mergeCellVertically(table, 1, 1, 2);
mergeCellVertically(innerTable, 1, 1, 2); // ????????????????????????????
// save to .docx file
try (FileOutputStream out = new FileOutputStream("./MAIN_table.docx")) {
doc.write(out);
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void setColumnWidth(XWPFTable table, int row, int col, int width) {
CTTblWidth tblWidth = CTTblWidth.Factory.newInstance();
tblWidth.setW(java.math.BigInteger.valueOf(width));
tblWidth.setType(STTblWidth.DXA);
CTTcPr tcPr = table.getRow(row).getCell(col).getCTTc().getTcPr();
if (tcPr != null) {
tcPr.setTcW(tblWidth);
} else {
tcPr = CTTcPr.Factory.newInstance();
tcPr.setTcW(tblWidth);
table.getRow(row).getCell(col).getCTTc().setTcPr(tcPr);
}
}
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);
//System.out.println(cell.getTableRow().getCtRow()); // wrong row in inner table when XWPFTable.createRow was used
CTVMerge vmerge = CTVMerge.Factory.newInstance();
if (rowIndex == fromRow) {
vmerge.setVal(STMerge.RESTART);
} else {
vmerge.setVal(STMerge.CONTINUE);
for (int i = cell.getParagraphs().size(); i > 0; i--) {
cell.removeParagraph(0);
}
cell.addParagraph();
}
CTTcPr tcPr = cell.getCTTc().getTcPr();
if (tcPr == null) {
tcPr = cell.getCTTc().addNewTcPr();
}
tcPr.setVMerge(vmerge);
}
}
}
Результат:
Если вопрос, почему так происходит, то подозреваю, что виноват XWPFTable.addColumn. Это основное различие между XWPFTable.createRow
и XWPFTable.insertNewTableRow
. Первый пытается заполнить новую добавленную строку таким количеством ячеек, сколько столбцов уже есть в таблице. Второй этого не делает и добавляет пустую строку.
Никогда не понимал такого поведения XWPFTable.createRow
. Почему необходимо заполнять новую добавленную строку таким количеством ячеек, сколько столбцов уже есть в таблице? Почему бы просто не позволить программисту добавить ячейки в строку?
Большое спасибо. Я долго не мог понять причину. Спасибо.
Пожалуйста, отредактируйте свой вопрос и правильно отформатируйте код.