Apache POI 设置单元格格式,包括 Table 总行的结果
Apache POI set cell Format That include the result of Table Total Row
可以在包含总计行的行 table 上设置单元格公式吗?
例如:我有一个总行如下所示:
Col[B] 有小计,Col[C] 也有小计
我需要 Col[D] 是 Col[B] 的总计 + Col[C] 的总计 Or / Them !
我试过这段代码:
import java.io.FileOutputStream;
import org.apache.poi.xssf.usermodel.*;
import org.apache.poi.ss.util.AreaReference;
import org.apache.poi.ss.util.CellReference;
class CreateExcelTable {
public static void main(String[] args) throws Exception {
try ( XSSFWorkbook workbook = new XSSFWorkbook(); FileOutputStream fileout = new FileOutputStream("Excel.xlsx")) {
//prepairing the sheet
XSSFSheet sheet = workbook.createSheet();
String[] tableHeadings = new String[]{"Heading1", "Heading2", "Heading3", "Heading4"};
String tableName = "Table1";
int firstRow = 0; //start table in row 1
int firstCol = 0; //start table in column A
int rows = 6; //we have to populate headings row, 4 data rows and 1 totals row
int cols = 4; //three columns in each row
for (int r = 0; r < rows; r++) {
XSSFRow row = sheet.createRow(firstRow + r);
for (int c = 0; c < cols; c++) {
XSSFCell localXSSFCell = row.createCell(firstCol + c);
if (r == 0) {
localXSSFCell.setCellValue(tableHeadings[c]);
} else if (r == 5) {
//totals row content will be set later
} else {
localXSSFCell.setCellValue(r + c);
}
}
}
//create the table
CellReference topLeft = new CellReference(sheet.getRow(firstRow).getCell(firstCol));
CellReference bottomRight = new CellReference(sheet.getRow(firstRow + rows - 1).getCell(firstCol + cols - 1));
AreaReference tableArea = workbook.getCreationHelper().createAreaReference(topLeft, bottomRight);
XSSFTable dataTable = sheet.createTable(tableArea);
dataTable.setName(tableName);
dataTable.setDisplayName(tableName);
//this styles the table as Excel would do per default
dataTable.getCTTable().addNewTableStyleInfo();
XSSFTableStyleInfo style = (XSSFTableStyleInfo) dataTable.getStyle();
style.setName("TableStyleMedium9");
style.setShowColumnStripes(false);
style.setShowRowStripes(true);
style.setFirstColumn(false);
style.setLastColumn(false);
//this sets auto filters
dataTable.getCTTable().addNewAutoFilter().setRef(tableArea.formatAsString());
//this sets totals properties to table and totals formulas to sheet
XSSFRow totalsRow = dataTable.getXSSFSheet().getRow(tableArea.getLastCell().getRow());
for (int c = 0; c < dataTable.getCTTable().getTableColumns().getTableColumnList().size(); c++) {
switch (c) {
case 0:
dataTable.getCTTable().getTableColumns().getTableColumnList().get(c).setTotalsRowLabel("Totals: ");
totalsRow.getCell(tableArea.getFirstCell().getCol() + c).setCellValue("Totals: ");
break;
case 1:
dataTable.getCTTable().getTableColumns().getTableColumnList().get(c).setTotalsRowFunction(org.openxmlformats.schemas.spreadsheetml.x2006.main.STTotalsRowFunction.SUM);
totalsRow.getCell(tableArea.getFirstCell().getCol() + c).setCellFormula("SUBTOTAL(109," + tableName + "[" + tableHeadings[c] + "])");
break;
case 2:
dataTable.getCTTable().getTableColumns().getTableColumnList().get(c).setTotalsRowFunction(org.openxmlformats.schemas.spreadsheetml.x2006.main.STTotalsRowFunction.SUM);
totalsRow.getCell(tableArea.getFirstCell().getCol() + c).setCellFormula("SUBTOTAL(109," + tableName + "[" + tableHeadings[c] + "])");
break;
case 3:
/// Formila on a totil row ??
totalsRow.getCell(tableArea.getFirstCell().getCol() + c).setCellFormula("Table1[[#Totals],[Heading2]]+Table1[[#Totals],[Heading3]]");
break;
default:
break;
}
}
//this shows the totals row
dataTable.getCTTable().setTotalsRowCount(1);
workbook.write(fileout);
}
}
}
但它不起作用,最终会自动删除总行!
我还尝试了另一种方法,将单元格公式设置为循环之外,但它以同样的错误结束!
有什么帮助吗?
使用 Excel
的 GUI 进行操作。然后保存 *.xlsx
文件。然后解压缩 *.xlsx
文件并查看 /xl/tables/table1.xml
。在那里你会发现:
...
<tableColumn name="Heading4" id="4" totalsRowFunction="custom">
<totalsRowFormula>Table1[[#Totals],[Heading2]]+Table1[[#Totals],[Heading3]]</totalsRowFormula>
...
因此第四个 table 列需要类型 custom
的 totalsRowFunction
和存储自定义公式的 totalsRowFormula
。
但是 sheet 也需要相应单元格中的公式。
所以翻译成Java
码:
...
dataTable.getCTTable().getTableColumns().getTableColumnList().get(c).setTotalsRowFunction(
org.openxmlformats.schemas.spreadsheetml.x2006.main.STTotalsRowFunction.CUSTOM);
dataTable.getCTTable().getTableColumns().getTableColumnList().get(c).addNewTotalsRowFormula().setStringValue(
tableName+"[[#Totals],["+tableHeadings[c-2]+"]]+"+tableName+"[[#Totals],["+tableHeadings[c-1]+"]]");
totalsRow.getCell(tableArea.getFirstCell().getCol()+c).setCellFormula(
tableName+"[[#Totals],["+tableHeadings[c-2]+"]]+"+tableName+"[[#Totals],["+tableHeadings[c-1]+"]]");
...
可以在包含总计行的行 table 上设置单元格公式吗?
例如:我有一个总行如下所示:
Col[B] 有小计,Col[C] 也有小计
我需要 Col[D] 是 Col[B] 的总计 + Col[C] 的总计 Or / Them !
我试过这段代码:
import java.io.FileOutputStream;
import org.apache.poi.xssf.usermodel.*;
import org.apache.poi.ss.util.AreaReference;
import org.apache.poi.ss.util.CellReference;
class CreateExcelTable {
public static void main(String[] args) throws Exception {
try ( XSSFWorkbook workbook = new XSSFWorkbook(); FileOutputStream fileout = new FileOutputStream("Excel.xlsx")) {
//prepairing the sheet
XSSFSheet sheet = workbook.createSheet();
String[] tableHeadings = new String[]{"Heading1", "Heading2", "Heading3", "Heading4"};
String tableName = "Table1";
int firstRow = 0; //start table in row 1
int firstCol = 0; //start table in column A
int rows = 6; //we have to populate headings row, 4 data rows and 1 totals row
int cols = 4; //three columns in each row
for (int r = 0; r < rows; r++) {
XSSFRow row = sheet.createRow(firstRow + r);
for (int c = 0; c < cols; c++) {
XSSFCell localXSSFCell = row.createCell(firstCol + c);
if (r == 0) {
localXSSFCell.setCellValue(tableHeadings[c]);
} else if (r == 5) {
//totals row content will be set later
} else {
localXSSFCell.setCellValue(r + c);
}
}
}
//create the table
CellReference topLeft = new CellReference(sheet.getRow(firstRow).getCell(firstCol));
CellReference bottomRight = new CellReference(sheet.getRow(firstRow + rows - 1).getCell(firstCol + cols - 1));
AreaReference tableArea = workbook.getCreationHelper().createAreaReference(topLeft, bottomRight);
XSSFTable dataTable = sheet.createTable(tableArea);
dataTable.setName(tableName);
dataTable.setDisplayName(tableName);
//this styles the table as Excel would do per default
dataTable.getCTTable().addNewTableStyleInfo();
XSSFTableStyleInfo style = (XSSFTableStyleInfo) dataTable.getStyle();
style.setName("TableStyleMedium9");
style.setShowColumnStripes(false);
style.setShowRowStripes(true);
style.setFirstColumn(false);
style.setLastColumn(false);
//this sets auto filters
dataTable.getCTTable().addNewAutoFilter().setRef(tableArea.formatAsString());
//this sets totals properties to table and totals formulas to sheet
XSSFRow totalsRow = dataTable.getXSSFSheet().getRow(tableArea.getLastCell().getRow());
for (int c = 0; c < dataTable.getCTTable().getTableColumns().getTableColumnList().size(); c++) {
switch (c) {
case 0:
dataTable.getCTTable().getTableColumns().getTableColumnList().get(c).setTotalsRowLabel("Totals: ");
totalsRow.getCell(tableArea.getFirstCell().getCol() + c).setCellValue("Totals: ");
break;
case 1:
dataTable.getCTTable().getTableColumns().getTableColumnList().get(c).setTotalsRowFunction(org.openxmlformats.schemas.spreadsheetml.x2006.main.STTotalsRowFunction.SUM);
totalsRow.getCell(tableArea.getFirstCell().getCol() + c).setCellFormula("SUBTOTAL(109," + tableName + "[" + tableHeadings[c] + "])");
break;
case 2:
dataTable.getCTTable().getTableColumns().getTableColumnList().get(c).setTotalsRowFunction(org.openxmlformats.schemas.spreadsheetml.x2006.main.STTotalsRowFunction.SUM);
totalsRow.getCell(tableArea.getFirstCell().getCol() + c).setCellFormula("SUBTOTAL(109," + tableName + "[" + tableHeadings[c] + "])");
break;
case 3:
/// Formila on a totil row ??
totalsRow.getCell(tableArea.getFirstCell().getCol() + c).setCellFormula("Table1[[#Totals],[Heading2]]+Table1[[#Totals],[Heading3]]");
break;
default:
break;
}
}
//this shows the totals row
dataTable.getCTTable().setTotalsRowCount(1);
workbook.write(fileout);
}
}
}
但它不起作用,最终会自动删除总行!
我还尝试了另一种方法,将单元格公式设置为循环之外,但它以同样的错误结束!
有什么帮助吗?
使用 Excel
的 GUI 进行操作。然后保存 *.xlsx
文件。然后解压缩 *.xlsx
文件并查看 /xl/tables/table1.xml
。在那里你会发现:
...
<tableColumn name="Heading4" id="4" totalsRowFunction="custom">
<totalsRowFormula>Table1[[#Totals],[Heading2]]+Table1[[#Totals],[Heading3]]</totalsRowFormula>
...
因此第四个 table 列需要类型 custom
的 totalsRowFunction
和存储自定义公式的 totalsRowFormula
。
但是 sheet 也需要相应单元格中的公式。
所以翻译成Java
码:
...
dataTable.getCTTable().getTableColumns().getTableColumnList().get(c).setTotalsRowFunction(
org.openxmlformats.schemas.spreadsheetml.x2006.main.STTotalsRowFunction.CUSTOM);
dataTable.getCTTable().getTableColumns().getTableColumnList().get(c).addNewTotalsRowFormula().setStringValue(
tableName+"[[#Totals],["+tableHeadings[c-2]+"]]+"+tableName+"[[#Totals],["+tableHeadings[c-1]+"]]");
totalsRow.getCell(tableArea.getFirstCell().getCol()+c).setCellFormula(
tableName+"[[#Totals],["+tableHeadings[c-2]+"]]+"+tableName+"[[#Totals],["+tableHeadings[c-1]+"]]");
...