.前言
前面的文章介绍了在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 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 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 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());
}
}
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 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 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 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());
}
}