0.前言
前面的文章介绍了在word中创建表格的行,这一篇中简单介绍一下合并单元格以及修改样式的一些方法。
1.合并单元格
分为合并行和合并列两种方式
void testXWPFTable1(){
System.out.println("开始执行");
try {
//定义word
XWPFDocument doc = new XWPFDocument();
//在word中创建一个表格(2行,3列)
XWPFTable table = doc.createTable(3,3);
//第一行数据
table.getRow(0).getCell(0).setText("1");
table.getRow(0).getCell(1).setText("2");
table.getRow(0).getCell(2).setText("3");
table.getRow(1).getCell(0).setText("4");
table.getRow(1).getCell(1).setText("5");
table.getRow(1).getCell(2).setText("6");
table.getRow(2).getCell(0).setText("7");
table.getRow(2).getCell(1).setText("8");
table.getRow(2).getCell(2).setText("9");
//横向合并,第一行的0和1
table.getRow(0).getCell(0).getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.RESTART);
table.getRow(0).getCell(1).getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE);
//竖向合并,
table.getRow(1).getCell(0).getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.RESTART);
table.getRow(2).getCell(0).getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.CONTINUE);
//导出
String path = "C:\\"; //文件路径
String name = "test1"; //文件名
path = path + "/" + name + ".docx";
File file = new File(path);
if (!file.exists()) {
file.createNewFile();
}
FileOutputStream out = new FileOutputStream(file);
doc.write(out);
}catch (IOException e){
e.printStackTrace();
}
}
效果:
提示:如果要合并第一列到第三列,单独写话每一个都要写一次,要不就参考用下面封装好的方法
我们也可以用封装好的方法:
/** * @Description: 跨列合并 * table * row:行 * fromCell:开始列 * toCell:结束列 */ public void mergeCellsHorizontal(XWPFTable table, int row, int fromCell, int toCell) { for (int cellIndex = fromCell; cellIndex <= toCell; cellIndex++) { XWPFTableCell cell = table.getRow(row).getCell(cellIndex); if ( cellIndex == fromCell ) { // The first merged cell is set with RESTART merge value cell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.RESTART); } else { // Cells which join (merge) the first one, are set with CONTINUE cell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE); } } } /** * @Description: 跨行合并 * table * col:列 * formRow:开始行 * toRow:结束行 */ public void mergeCellsVertically(XWPFTable table, int col, int fromRow, int toRow) { for (int rowIndex = fromRow; rowIndex <= toRow; rowIndex++) { XWPFTableCell cell = table.getRow(rowIndex).getCell(col); if ( rowIndex == fromRow ) { // The first merged cell is set with RESTART merge value cell.getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.RESTART); } else { // Cells which join (merge) the first one, are set with CONTINUE cell.getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.CONTINUE); } } }
再测试一下导入word中合并单元格的方法
要导入的表格如下:
测试代码:
void testXWPFTable2(){ System.out.println("开始执行"); try { InputStream is = new FileInputStream("C:\\test.docx"); //定义word XWPFDocument doc = new XWPFDocument(is); //获取word中所有的表格 List<XWPFTable> tableList = doc.getTables(); XWPFTable table1 = tableList.get(0); //表格中第一个表 table1.createRow(); //创建一行 //合并单元格 mergeCellsHorizontal(table1,0,0,2); mergeCellsVertically(table1,1,1,2); //导出 String path = "C:\\"; //文件路径 String name = "test2"; //文件名 path = path + "/" + name + ".docx"; File file = new File(path); if (!file.exists()) { file.createNewFile(); } FileOutputStream out = new FileOutputStream(file); doc.write(out); }catch (IOException e){ e.printStackTrace(); } }
效果:
2.addRow合并的问题:
上面验证了合并单元格的一些方式不论是手动创建表格,还是读取表格后,都能正常合并。包括使用createRow这个方法后,也能正常合并。但是使用addRow方法后,发现并不能正常使用。例子如下:
我们先读取一个本地文件
我们在红色箭头处通过addRow方法插入一个新行,然后执行合并操作,看看效果。
参考代码:
void testXWPFTable2(){ System.out.println("开始执行"); try { InputStream is = new FileInputStream("C:\\test.docx"); //读取了一个4*4的表格 //定义word XWPFDocument doc = new XWPFDocument(is); //获取word中所有的表格 List<XWPFTable> tableList = doc.getTables(); XWPFTable table1 = tableList.get(0); //表格中第一个表 CTRow ctrow = null; try { ctrow = CTRow.Factory.parse(table1.getRow(0).getCtRow().newInputStream()); //复制 } catch (XmlException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } XWPFTableRow newRow = new XWPFTableRow(ctrow, table1); newRow.getCell(0).setText("A"); newRow.getCell(1).setText("B"); newRow.getCell(2).setText("C"); table1.addRow(newRow,1); mergeCellsHorizontal(table1,0,1,3); //合并列(未涉及新增行) mergeCellsHorizontal(table1,1,0,1); //合并列(涉及新增行) mergeCellsVertically(table1,2,1,4); //合并行(涉及新增行) mergeCellsVertically(table1,0,0,2); //合并行(涉及新增行) //导出 String path = "C:\\"; //文件路径 String name = "test2"; //文件名 path = path + "/" + name + ".docx"; File file = new File(path); if (!file.exists()) { file.createNewFile(); } FileOutputStream out = new FileOutputStream(file); doc.write(out); }catch (IOException e){ e.printStackTrace(); } }
效果如下:
可以看到,我们使用addRow新增的行是无法进行合并的,即使合并的单元格中包含也会被忽略掉。
官方文档中并没有详细说明过这个问题,但是应该是跟我们复制有关。
最后终于找到了解决办法,加入一个函数commitTabkeRows,在合并完调用这个函数即可。
static void commitTableRows(XWPFTable table) {
int rowNr = 0;
for (XWPFTableRow tableRow : table.getRows()) {
table.getCTTbl().setTrArray(rowNr++, tableRow.getCtRow());
}
}
那么,合并以后调用即可:
void testXWPFTable2(){ System.out.println("开始执行"); try { InputStream is = new FileInputStream("C:\\test.docx"); //读取了一个4*4的表格 //定义word XWPFDocument doc = new XWPFDocument(is); //获取word中所有的表格 List<XWPFTable> tableList = doc.getTables(); XWPFTable table1 = tableList.get(0); //表格中第一个表 CTRow ctrow = null; try { ctrow = CTRow.Factory.parse(table1.getRow(0).getCtRow().newInputStream()); //复制 } catch (XmlException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } XWPFTableRow newRow = new XWPFTableRow(ctrow, table1); newRow.getCell(0).setText("A"); newRow.getCell(1).setText("B"); newRow.getCell(2).setText("C"); table1.addRow(newRow,1); mergeCellsHorizontal(table1,0,1,3); //合并列(未涉及新增行) mergeCellsHorizontal(table1,1,0,1); //合并列(涉及新增行) mergeCellsVertically(table1,2,1,4); //合并行(涉及新增行) mergeCellsVertically(table1,0,0,2); //合并行(涉及新增行) commitTableRows(table1); //导出 String path = "C:\\"; //文件路径 String name = "test2"; //文件名 path = path + "/" + name + ".docx"; File file = new File(path); if (!file.exists()) { file.createNewFile(); } FileOutputStream out = new FileOutputStream(file); doc.write(out); }catch (IOException e){ e.printStackTrace(); } }
效果:
3.总结
上面用到了很多封装好的函数,在此总结一下
1.跨列合并
/** * @Description: 跨列合并 * table * row:行 * fromCell:开始列 * toCell:结束列 */ public void mergeCellsHorizontal(XWPFTable table, int row, int fromCell, int toCell) { for (int cellIndex = fromCell; cellIndex <= toCell; cellIndex++) { XWPFTableCell cell = table.getRow(row).getCell(cellIndex); if ( cellIndex == fromCell ) { // The first merged cell is set with RESTART merge value cell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.RESTART); } else { // Cells which join (merge) the first one, are set with CONTINUE cell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE); } } }
2.跨行合并
/** * @Description: 跨行合并 * table * col:列 * formRow:开始行 * toRow:结束行 */ public void mergeCellsVertically(XWPFTable table, int col, int fromRow, int toRow) { for (int rowIndex = fromRow; rowIndex <= toRow; rowIndex++) { XWPFTableCell cell = table.getRow(rowIndex).getCell(col); if ( rowIndex == fromRow ) { // The first merged cell is set with RESTART merge value cell.getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.RESTART); } else { // Cells which join (merge) the first one, are set with CONTINUE cell.getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.CONTINUE); } } }
3.addRow方法封装
/** * 复制一行到一个新位置插入 * @param sourceTableRow 要复制的行 * @param pos 要插入的位置 * @return * @throws Exception */ static XWPFTableRow insertNewTableRow(XWPFTableRow sourceTableRow, int pos) throws Exception { XWPFTable table = sourceTableRow.getTable(); CTRow newCTRrow = CTRow.Factory.parse(sourceTableRow.getCtRow().newInputStream()); XWPFTableRow tableRow = new XWPFTableRow(newCTRrow, table); table.addRow(tableRow, pos); return tableRow; }
4.重新合并单元格
/** * 合并单元格,在使用过addRow方法并合并单元格后再调用 * @param table */ static void commitTableRows(XWPFTable table) { int rowNr = 0; for (XWPFTableRow tableRow : table.getRows()) { table.getCTTbl().setTrArray(rowNr++, tableRow.getCtRow()); } }